I try to load an HTML page from a remote server into a PHP script, which should manipulate the HTML with the DOMDocument class. But I have seen, that the DOMDocument class removes some parts of the Javascript, which comes with the HTML page. There are some things like:
<script type="text/javascript">
//...
function printJSPage() {
var printwin=window.open('','haha','top=100,left=100,width=800,height=600');
printwin.document.writeln(' <table border="0" cellspacing="5" cellpadding="0" width="100%">');
printwin.document.writeln(' <tr>');
printwin.document.writeln(' <td align="left" valign="bottom">');
//...
printwin.document.writeln('</td>');
//...
}
</script>
But the DOMDocument changes i.e. the line
printwin.document.writeln('</td>');
to
printwin.document.writeln(' ');
and also a lot of others things (i.e. the last script tag is no longer there. As the result I get a complete destroyed page, which I cannot send further.
So I think, DOMDocument has problems with the HTML tags within the Javascript code and tries to correct the code, to produce a well-formed document. Can I prevent the Javascript parsing within DOMDocument?
The PHP code fragment is:
$stdin = file_get_contents('php://stdin');
$dom = new \DOMDocument();
#$dom->loadHTML($stdin);
return $dom->saveHTML(); // will produce wrong HTML
//return $stdin; // will produce correct HTML
I have stored both HTML versions and have compared both with Meld.
I also have tested
#$dom->loadXML($stdin);
return $dom->saveHTML();
but I don't get any things back from the object.
Here's a hack that might be helpful. The idea is to replace the script contents with a string that's guaranteed to be valid HTML and unique then replace it back.
It replaces all contents inside script tags with the MD5 of those contents and then replaces them back.
$scriptContainer = [];
$str = preg_replace_callback ("#<script([^>]*)>(.*?)</script>#s", function ($matches) use (&$scriptContainer) {
$scriptContainer[md5($matches[2])] = $matches[2];
return "<script".$matches[1].">".md5($matches[2])."</script>";
}, $str);
$dom = new \DOMDocument();
#$dom->loadHTML($str);
$final = strtr($dom->saveHTML(), $scriptContainer);
Here strtr is just convenient due to the way the array is formatted, using str_replace(array_keys($scriptContainer), $scriptContainer, $dom->saveHTML()) would also work.
I find it very suprising that PHP does not properly parse HTML content. It seems to instead be parsing XML content (wrongly so as well because CDATA content is parsed instead of being treated literally). However it is what it is and if you want a real document parser then you should probably look into a Node.js solution with jsdom
If you have a <script> within a <script>, the following (not so smart) solution will handle that. There is still a problem: if the <script> tags are not balanced, the solution will not work. This could occur, if your Javascript uses String.fromCharCode to print the String </script>.
$scriptContainer = array();
function getPosition($tag) {
return $tag[0][1];
}
function getContent($tag) {
return $tag[0][0];
}
function isStart($tag) {
$x = getContent($tag);
return ($x[0].$x[1] === "<s");
}
function isEnd($tag) {
$x = getContent($tag);
return ($x[0].$x[1] === "</");
}
function mask($str, $scripts) {
global $scriptContainer;
$res = "";
$start = null;
$stop = null;
$idx = 0;
$count = 0;
foreach ($scripts as $tag) {
if (isStart($tag)) {
$count++;
$start = ($start === null) ? $tag : $start;
}
if (isEnd($tag)) {
$count--;
$stop = ($count == 0) ? $tag : $stop;
}
if ($start !== null && $stop !== null) {
$res .= substr($str, $idx, getPosition($start) - $idx);
$res .= getContent($start);
$code = substr($str, getPosition($start) + strlen(getContent($start)), getPosition($stop) - getPosition($start) - strlen(getContent($start)));
$hash = md5($code);
$res .= $hash;
$res .= getContent($stop);
$scriptContainer[$hash] = $code;
$idx = getPosition($stop) + strlen(getContent($stop));
$start = null;
$stop = null;
}
}
$res .= substr($str, $idx);
return $res;
}
preg_match_all("#\<script[^\>]*\>|\<\/script\>#s", $html, $scripts, PREG_OFFSET_CAPTURE|PREG_SET_ORDER);
$html = mask($html, $scripts);
libxml_use_internal_errors(true);
$dom = new DOMDocument();
$dom->loadHTML($html);
libxml_use_internal_errors(false);
// handle some things within DOM
echo strtr($dom->saveHTML(), $scriptContainer);
If you replace the "script" String within the preg_match_all with "style" you can also mask the CSS styles, which can contain tag names too (i.e. within comments).
Related
I have a php function which simply returns a value, I want to assign that value to a variable in my javascript code in my frontend page.
email_data() function in functions.php:
function email_data()
{
$a = 0;
$form_to_DB = WPCF7_Submission::get_instance();
if ( $form_to_DB )
$formData = $form_to_DB->get_posted_data();
$type = implode(',', $formData['type']);
$type = $type . ' ' . $formData['type-other'];
$place = implode(',', $formData['place']);
$place = $place . ' ' . $formData['place-other'];
$Postcode = $formData['Postcode'];
$date = $formData['date'];
$location_long = $formData['cf7-location-lng'];
$location_lat = $formData['cf7-location-lat'];
$location_litter = $formData['cf7-location-url'];
$location_litter = $formData['location-340'];
$comment = $formData['comment'];
if ($formData != null)
{
echo "Hi there! I want to report illegal dumping which consists of $type at $place area. The coordinates of the dumping are Lat: $location_lat, Long: $location_long.";
}
else
{
echo "Please fill the above form first!"
}
return $a;
}
I have some html and javascript code on one of my pages which I am using to display a form. Now, I want the variable returned by the php code to be saved in a JS variable. I have tried doing so many things but nothing works out, I am a newbie in WordPress dev sorry.
Check out wp_localize_script. It allows you to pass PHP variables to the browser, where your javascript can then read.
I want to ask advice from you guys since I have a problem of showing html tags within table structure.
Actually, I want to show is "link".
To be clear I will explain you more details.
I am making auto generated table structure view with the help of javascript and jquery that shows data from database and want to show these data as table structure which also include the link that allows user to edit the data. That's it.
See the below image:
As you can see, links are showing as normal characters.
So anyone who knows the answer please advice me.
Below is the code:
//php
$sql = "SELECT * FROM v_category";
$dbaction = new db_action($sql,'G');
$result = $dbaction->db_process();
$dataRows = "Category Name|Remark|Edit|";
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
$ctgr_id = $row["ctgr_id"];
$ctgr_name = $row["ctgr_name"];
$remark = $row["remk"];
$link = "<a href='?cv=ms-category&mode=2&id=$ctgr_id'>link</a>";
$dataRows = $dataRows . "**row**" . $ctgr_name . "|";
$dataRows = $dataRows . $remark . "|";
$dataRows = $dataRows . $link;
}
} else {
echo "0 results";
}
echo '<div id="draw-grid" class="tbl-responsive" style="overflow-x:auto;"><script>DrawTable("draw-grid","'.$dataRows.'");</script></div>';
//javascript
function DrawTable(Container,dataRows)
{
dataRows = dataRows.split(ROW_SPLITTER);
var tTable=$('<table>');
//draw the table header
tTable.append(drawHeader(dataRows[0]));
//draw the table body
tTable.append(drawBody(dataRows));
//add table to wrapper container first and then add into the parent container
$('<div>').append(tTable)
.appendTo($('#'+Container));
return;
}
function drawHeader(headerRow)
{
var headerRowColumns = headerRow.split("|");
var tblRow=$('<tr>');
headerRowColumns.forEach(function(element,index) {
$('<th>')
.text(element)
.appendTo(tblRow);
});
return $('<thead>').append(tblRow);
}
function drawBody(objRows)
{
var tBody=$('<tbody>');
objRows.forEach(
function(objRow,index)
{
if(index!=0)
{
tBody.append(drawBodyRow(objRow,index));
}
});
return tBody;
}
function drawBodyRow(bodyRow,rowIndex)
{
var bodyRowColumns = bodyRow.split("|");
var tRow=$('<tr>');
bodyRowColumns.forEach(function(element,columnIndex)
{
$('<td>').text(element).appendTo(tRow);
});
return tRow;
}
$('<td>').text(element).appendTo(tRow);
In this line and others like it, you're setting the inner text of the matched elements to be a value.
This is actually a good thing in almost all cases. You don't want to be interjecting arbitrary HTML into a context where a text value is intended. Otherwise, you open up yourself to potential security issues, or at least, invalid HTML.
What you should be doing instead, if you really intend to inject HTML, is to append those elements to this one.
Your code has other problems too...
$link = "<a href='?cv=ms-category&mode=2&id=$ctgr_id'>link</a>";
In this line, you're interpolating arbitrary data into a URL and into HTML, with nothing being escaped. Use http_build_query() to escape the data for the query string. Then, be sure to use htmlspecialchars() for any arbitrary data injected into HTML to ensure it's escaped for that context.
I'm trying to create an Edit Modal. Provided that I have the html code for this, I write this javascript/jquery code:
<script type='text/javascript'>
$(function() {
<?php
$q = $db->query("select * from tblUnit where unitStatus <> '2'");
while($r = $q->fetch(PDO::FETCH_ASSOC)){
echo " <script type'text/javascript'> alert('1');</script>";
$unitID = $r['unitID'];
$unitStatus = $r['unitStatus'];
$unitNumber = $r['unitNumber'];
$floorNumber = $r['floorCode'];
$unitType = $r['unitType'];
$t = $db->query("select floorLevel, floor_buildingID from tblFloors where floorLevel = '$floorNumber'");
while( $u = $t->fetch(PDO::FETCH_ASSOC)){
$floorLevel = $u['floorLevel'];
$floor_buildingID = $u['floor_buildingID'];
$w = $db->query("select unitTypeName from tblUnitType where unitTypeID = $unitType");
while($x = $w->fetch(PDO::FETCH_ASSOC)){
$unitTypeName = $x['unitTypeName'];
?>
$("#editModal<?php echo $unitID; ?>").click(function(){
$("#editUnitNumber").val("<?php echo $unitNumber;?>");
$("#editUnitType").val("<?php echo $unitType; ?>").material_select('update');
$("#editFloorNumber").val("<?php echo $floorNumber; ?>");
});
<?php }}}?>
});
The code above is used to write the data from the modal, but instead it output this:
$("#editModal5").click(function(){ $("#editUnitNumber").val("12002"); $("#editUnitType").val("4").material_select('update'); $("#editFloorNumber").val("12"); }); });
How do I solve that? What causes this?
Use json to pass data from php to javascript, instead of echoing everything out in one place. It may seem an overkill but it's readable, and is more beneficial on the long run.
The code below is not tested, but it should give you a general idea on how to approach these things. I did not include the second and third queries within the first while loop. You can nest the results from those queries in the $unit array and access the relevant data via additional loops in javascript.
Also, ideally you wouldn't just echo out the decoded array right after the php, a better solution would be to call a function in the footer, that would generate a script tag with all data that is used by javascript. Another approach is to use AJAX and get a json response only when you need it, then you would feed that same json to the loop.
<?php
$q = $db->query("select * from tblUnit where unitStatus <> '2'");
$units = [];
while($r = $q->fetch(PDO::FETCH_ASSOC)){
$unit = [
'unitID' => $r['unitID'],
'unitStatus' => $r['unitStatus'],
'unitNumber' => $r['unitNumber'],
'floorNumber' => $r['floorCode'],
'unitType' => $r['unitType']
];
$units[] = $unit;
}
$units_json = json_encode($units);
?>
<script type='text/javascript'>
$(function() {
var units = '<?php echo $units_json ?>';
var units_array = JSON.parse(units);
// do some validation here
for (var i = 0; i < units_array.length; i++) {
// do some validation here
$("#editModal" + units_array[i].unitID).click(function(){
$("#editUnitNumber").val(units_array[i].unitNumber);
$("#editUnitType").val(units_array[i].unitType).material_select('update');
$("#editFloorNumber").val(units_array[i].floorNumber);
});
};
});
</script>
I have the following HTML fragment, using PHP and JavaScript:
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script>
var imageIndex = 0; // index into imageNames array
var imageHeight = 400; // height of image; changed by user clicking size buttons
var imageNames; // names of images user can view in this album
function pageLoaded() // execute this when the page loads.
{
// PHP -- generate the array of image file names
<?php
function getImageNames($directory)
{
$handle = opendir($directory); // looking in the given directory
$file = readdir($handle); // get a handle on dir,
while ($file !== false) // then get names of files in dir
{
$files[] = $file;
$file = readdir($handle);
}
if ($files[0] === ".") { unset($files[0]); } // Unix specific?
if ($files[1] === "..") { unset($files[1]); }
foreach($files as $index => $file) // only keep files with image extensions
{ $pieces = explode(".", $file);
$extension = strtolower(end($pieces));
if ($extension !== "jpg") { unset($files[$index]); }
}
$files = array_values($files); // reset array
natcasesort($files); // and sort it.
return $files;
}
?>
<?php $imageDirectory = $_GET['directory'] . '/';
$imageNames = getImageNames($imageDirectory);
?>
imageNames = <?php echo json_encode($imageNames); ?>;
imageHeight = 400;
imageIndex = 0;
reloadImage(); // loads the first image based on height and index
}
There is more after this, but this part doesn't refer to anything there, and my problem already exists by this point in the HTML output.
The problem is that, 5 lines from the end, I do a json_encode of an array of filenames. The output I get from this looks thusly:
imageNames = [{"59":"01-hornAndMusic.JPG","58":"02-DSC_0009.JPG","57":"03-DSC_0010.JPG","56":"04-Discussion.JPG","55":"05-DSC_0015.JPG","54":"06-DSC_0016.JPG","53":"07-DSC_0019.JPG","52":"08-strings.JPG","51":"09-strings2.JPG","50":"10-rehearsing.JPG","49":"11-StringsBigger2-001.JPG","48":"12-DSC_0041.JPG","47":"13-DSC_0046.JPG","46":"14-ensemble.JPG","45":"15-ensemble2.JPG","44":"16-DSC_0052.JPG","43":"17-rehearsing3.JPG","42":"18-rehearsing4.JPG","41":"19-rehearsing-001.JPG","40":"20-stringsBigger2.JPG","39":"21-rehearsing-002.JPG","38":"22-rehearsing-003.JPG","37":"23-ensemble3.JPG","36":"24-winds.JPG","35":"25-rehearsing-004.JPG","34":"26-stringsEvenBigger.JPG","33":"27-concentration.JPG","32":"28-concertMistress2.JPG","31":"29-stringsMore.JPG","30":"30-stringsMore-001.JPG","29":"31-stringsMore-002.JPG","28":"32-stringsMore-003.JPG","27":"33-stringsMore-004.JPG","26":"34-stringsMore-005.JPG","25":"35-DSC_0076.JPG","24":"36-stringsMore-007.JPG","23":"37-stringsMore-008.JPG","22":"38-stringsMore-009.JPG","21":"39-oboes.JPG","20":"40-winds-001.JPG","19":"41-DSC_0085.JPG","18":"42-DSC_0086.JPG","17":"43-percussion.JPG","16":"44-DSC_0088.JPG","15":"45-violinAtRest.JPG","14":"46-laughterInTheWoodwinds.JPG","13":"47-conducting-001.JPG","12":"48-DSC_0095.JPG","11":"49-DSC_0096.JPG","10":"50-AllTogetherNow.JPG","9":"51-DSC_0106.JPG","8":"52-horns.JPG","7":"53-DSC_0111.JPG","6":"54-conducting.JPG","5":"55-conducting-002.JPG","4":"56-conducting-003.JPG","3":"57-conducting-005.JPG","2":"58-DSC_0120.JPG","1":"59-DSC_0122.JPG","0":"60-everybody.JPG"}];
so I have the keys as well as the values of this hybrid PHP map/array thingie. What I want is just the values, put into a string array in the JavaScript.
I've gotten this to work sometimes, but not others, and I don't know the difference.
I think applying array_values function on $imageNames before encoding them should do the trick.
imageNames = <?php echo json_encode(array_values($imageNames)); ?>;
I'd do this:
imageNames = <?php echo json_encode(array_values($imageNames)); ?>;
I have the following div that has a number generated by jQuery:
HTML:
<td id="Total" class="total">
</td>
jQuery:
var sum = 0;
$(".item-price").each(function() {
var NewQuoteTotal = $(this).html().replace('£', '')
sum += parseInt(NewQuoteTotal);
})
console.log(sum)
$(".total").text('£' + sum)
I need to get the generated number from that element so that I can use it in PHP to be displayed elsewhere.
I've meddled with DOM (Which I don't know):
$dom = new domDocument;
$html = file_get_contents("FILELOCATION"); //I don't use FILELOCATION, that's just a placeholder for StackOverflow.
$dom->loadHTML($html);
$dom->preserveWhiteSpace = false;
$thePrice = $dom->getElementById("Total");
if(!$thePrice) {
die("Element Not Found!");
}
echo "Element is there!";
$xpath = new DOMXPath($dom);
$divContent = $xpath->query('//td[id="Total"]');
echo $divContent;
And tried to use jQuery to $.post() a variable containing the number but I've had no success.
$.post('/path/to/my/php/script.php', {total: $('#Total').text()}, function(){
//what to do with the returned data from the server
});
And in script.php (as indicated above):
$total = isset($_POST['total']) ?: false;
if($total !== false):
//you can use $total now
endif;
I can't believe I didn't think of it earlier, but I just made the variable in PHP rather than jQuery...
Thanks for all the help!