I've this PHP page:
<?php
$lines = array();
$lines[] = "I am happy";
$lines[] = "I'm happy";
foreach ($lines as $line){
$message = htmlspecialchars($line);
?>
<div onclick="alert('<?=$message?>');"><div>
<?php
}
It generates this HTML results:
<div onclick="alert('I am happy');"><div>
<div onclick="alert('I'm happy');"><div>
This code seems to be correct, however, clicking on second "div" element an error occurs.
The ' char is equivalent to ' and javascript generates an error:
alert('I'm happy');"
I solved this problem adding to code addslashes() PHP function:
$lines = array();
$lines[] = "I am happy";
$lines[] = "I'm happy";
foreach ($lines as $line){
$message = htmlspecialchars(addslashes($line));
?>
<div onclick="alert('<?=$message?>');"><div>
<?php
}
Correct results:
<div onclick="alert('I am happy');"><div>
<div onclick="alert('I\'m happy');"><div>
My question:
Is this the right/best solution?
Which is the best practice to manage this kind of problems?
Don't try to generate JavaScript string literals by mashing strings together. json_encode will do it for you along with all the escaping (', ", new lines, etc) that you need for JS. It is preferred to addslashes because it is designed for the target data format and isn't generic (generic escaping solutions tend to miss things).
Encode data for HTML attribute values as the last thing you do to the data before putting it in the value. Don't encode for HTML before putting data into JavaScript.
foreach ($lines as $line){
$message = json_encode($line);
$javascript = "alert($message)";
$html = htmlspecialchars($javascript);
?>
<div onclick="<?= $html ?>"><div>
<?php
}
That said, a modern approach would generally keep the JavaScript separate and store the data in a data attribute.
You should also avoid putting click events on div elements, they aren't designed to be user controls so they can't (without more mucking about) be triggered by (for example) focusing the element and pressing enter which creates accessibility problems.
foreach ($lines as $line){
$html = htmlspecialchars($line);
?>
<button type="button" data-message="<?= $html ?>">...</button>
<?php
}
with
<script>
function buttonAlert(event) {
var message = event.target.dataset.message;
if (message) {
alert(message);
}
}
addEventListener("click", buttonAlert);
</script>
Your correct result is actually wrong, and would output I'm happy instead of I'm happy.
Asside from that, yes your solution will work and i don't see any problem with that way of doing in your particular context.
You can use below code
<?php
$lines = array();
$lines[] = "I am happy";
$lines[] = "I'm happy";
foreach ($lines as $line){ ?>
<div onclick="alert('<?=addslashes($line); ?>');"><div>
<?php } ?>
Related
Using simple PHP and Javascripet (no JSON, AJAX, or anything fancy) I am trying to echo a javascript onClick event function. This onClick function takes two strings, and as a start I want to see those strings using the "alert" function. Below is my code in the html/php file::
<DIV id="show">
!-- few more lines here -->
<?PHP
$CONN = mysqli_connect($SERVER_w, $USER_w, $PASS_w, $DBNAME_w);
$SQL = "SELECT * from COUNTRYTABLE";
$RESULT = mysqli_query($CONN, $SQL);
$NUM_RECORDS = mysqli_num_rows($RESULT);
echo "<BR>";
for($x = 1; $x<=$NUM_RECORDS; $x++)
{ $ROW = mysqli_fetch_array($RESULT, MYSQLI_ASSOC);
//the main line::
echo "<button onClick=\"Show_Pair(\"" . $ROW['CONTINENT'] . "\",\"" .
$ROW['COUNTRY'] . "\")\"> Show! </button> <BR>";
}
mysqli_free_result($RESULT);
mysqli_close($CONN);
?>
</DIV>
The Javascript function is a simple one:
function Show_Pair_In_Alert(CON, CTR)
{
alert(CON + CTR);
}
When the PHP evaluates, the HTML looks like follows:
<DIV id="show">
<p>CONTINENT - COUNTRY Linkage: </p><BR><BR><button
onClick="Show_Pair_In_Alert("AFRICA_EAST","Comoros")">Show</button> <BR>
<button onClick="Show_Pair_In_Alert("AFRICA_EAST","Eritrea")">Show</button>
<BR>
<button onClick="Show_Pair_In_Alert("AFRICA_EAST","Kenya")">Show</button>
<BR>
</DIV>
HOWEVER, when I look at the developer tools/console thingy in Chrome, I see the following error::
Uncaught SyntaxError: Unexpected token }, and this error occurrs just above the end of the and below the last button.. theres a red circle with a yellow cross in it.. as can be seen in the image below
Would appreciate any feedback.. just to reiterate.. im not using any JSON, AJAX, anything... just trying to achieve something fairly complex for my begineer level :P.. thank you very much for your assistance in advance!!
My 1 file is city.html which contains the following code
<script language="javascript">alert("Page Called"); </script>
'Bhubaneshwar', 'Orissa', 'India'
My another file index.php contains the following code
$x=file_get_contents("city.html");
$x=array($x);
echo $x[0];
It shows the following output
'Bhubaneshwar', 'Orissa', 'India'
But I want single word output like this.
When I print $x[0], it should be Bhubaneshwar
When I print $x[1], it should be Orissa
When I print $x[2], it should be India
First you need to remove script tags
$x = file_get_contents("city.html");
$x = preg_replace('%<script[^>]*>.*?</script>%/m', '', $x);
and then you can use explode:
$array = explode(',', $x);
then you can trim and remove quotes:
$array = array_map(function($item) {
return preg_replace("/^'|'$/", trim($item));
}, $array);
Use explode to convert string to array:-
// Remove script tag
$string = preg_replace('#<script(.*?)>(.*?)</script>#is', '', $x);
// $string = str_replace(' ', '', $string); // Remove space from string
$string = preg_replace('/\s+/', '', $string); // Remove whitespace from string
// explode string
$x = explode(',',$string);
Hope it will help you :)
Try,
$x=file_get_contents("city.html");
$x=array($x);
$html = preg_replace('#<script[^>]*?.*?</script>#', '', $x);
$str = str_replace(', ', ',', $html);
$x = explode(',',trim($str[0]));
$remove[] = "'";
$result = str_replace( $remove, "", $x );
foreach($result as $cities)
{
echo $cities . "<br>";
}
Here is code that first removes the preceding script tag(s) and breaks down the remainder into an array:
$x=array_pop(explode('</script>', $x));
$x=preg_split("/'\s*,\s*'/", trim(trim($x), "'"));
The first of those two statements is only needed if you keep that script tag inside your HTML, which seems to be there for testing only.
To display the result, you could do this:
foreach($x as $item) {
echo $item . "<br>";
}
Output:
Bhubaneshwar
Orissa
India
Considerations
It is unusual to have such data format inside HTML files. HTML is intended for rendering data in a user-friendly manner, and that representation does not really fit.
If you are the creator of the HTML file, then consider moving to a JSON format. In that case your file would be named city.json and would have this content (the double quotes and brackets are required):
["Bhubaneshwar", "Orissa", "India"]
And the code would make use of JSON functions like this:
$json=file_get_contents("city.json");
$x=json_decode($json);
This way you really use standards, and the code is compact.
You could again display the contents of $x like before:
foreach($x as $item) {
echo $item . "<br>";
}
Output:
Bhubaneshwar
Orissa
India
If you are the creator of that file, and use PHP to create it, then make use of JSON functions as well, as follows:
$x = array("Bhubaneshwar", "Orissa", "India");
file_put_contents ("city.json", json_encode($x));
I know this topic was already discussed a few times but I can't seem to find what I'm doing wrong.
What I'm trying to do:
The user types in a number and by clicking on the button creates a table with that number of columns.
Heres the php:
<?php
$twig = require_once('bootstrap.php');
$hostname = 'localhost';
$username = 'root';
$password = '';
$conn = new PDO("mysql:host=$hostname;dbname=mydb", $username, $password);
echo $twig->render('index.html', array());
$numOfRows = 1;
if(isset($_POST['button'])){
$numOfRows = $_POST['num_input'];
}
html/javascript:
<html>
<head>
<script>
function insertRows(){
var numOfRows = <?php echo json_encode($numOfRows) ?>;
var out = "<table><tr><th>test</th>";
for (i = 0; i < numOfRows; i++){
out += "<th>test</th>";
}
out += "</tr></table>";
document.getElementById("table").innerHTML = out;
}
</script>
</head>
<body>
<form action="index.php" method="post">
<textarea id="num_input" name ="num_input"></textarea>
<button type="button" name="button" onclick="insertRows()"> Go </button>
</form>
<p id="table"></p>
</body>
</html>
Theres no error or anything since I'm not using a IDE, just doing it in vim but the error is that is just doesn't happen. If i change "numOfRows" in the for loop to a number it works, so I'm pretty sure the json_encode is the problem.
Thanks!
EDIT:
Just to test it, I used a string variable $str = "test"; the php file, and instead of using the for loop, I just edited javascript to
var str = <?php echo json_encode($str); ?>;
alert(str);
and I also tried
var str = <?php echo $str; ?>;
alert(str);
but nothing works.
json_encode is not necessary in this case.
Simply replace
var numOfRows = <?php echo json_encode($numOfRows); ?>;
with
var numOfRows = <?php echo (int)$numOfRows; ?>;
Edit: You are missing a ; on the
<?php echo json_encode($numOfRows) ?>
Should be
<?php echo json_encode($numOfRows);?>
And in these cases, if would be good to check the server log, this will automaticly make you better at finding these mistakes yourself.
You are mixing up ints and strings. The database will in PHP always return strings and the way you are using the variable as an int in a for loop.
The following change i believe would achieve the right result.
$numOfRows = intval($_POST['num_input']);
Where you use PHP's conversion to integer function there is at a global level.
You did not forget any $. JS does not need $ for variables.
As far as your json_encode is concerned, if you are just passing an integer from PHP to JS, there is no need to json_encode. Just pass the variable to JS as <?=$numOfRows?> in the JS source.
i have the following code, but it will not work. i am trying to create a script output:
echo "<script type=\"text/javascript\"><!--\n";
echo "SLIDES = new slideshow(\"SLIDES\")\n";
// Now loop through the files, echoing out a new select option for each one
foreach( $files as $fname ) {
echo 's = new slide()\n';
echo 's.src = \"http://cashbackflorida.com/wpradmin/modules/wprrets/photos/'.$result ->MLS.'/'{$fname}\n\"';
echo 's.width = \"560\"\n';
echo 's.height = \"420\"\n';
echo 's.alt = \"{$fname}\"\n';
echo 's.text = unescape(\"\")\n';
echo 's.link = \"\"\n';
echo 's.target = \"\"\n';
echo 's.attr = \"\"\n';
echo 's.filter = \"\"\n';
echo 'SLIDES.add_slide(s)\n';
}
echo '--></script>\n';
Don't do it this way. Just output the array to JavaScript and deal with it there.
var files = <?php echo json_encode($files); ?>;
You'll find the problem in your string escaping
echo 's.height = \"420\"\n';
You can't escape in single quote strings like that. So try this
echo "s.height = \"420\"\n";
You do NOT need to escape single quotes within double quotes or visa versa, but you can only get a newline character like that in a double quote string.
I would recommend HEREDOC for this kind of string writing though.
$fnamej = json_encode($fname);
echo << EOT
s.height = "420";
s.alt = $fnamej;
EOT;
I am also inclined to say that you'd be better off handling this in javascript. This may end up behaving very badly all of a sudden, and it will take up more bandwidth.
I'm trying to create a nice and easy iterator and it worked at first, then I realized I'd need more information for the function so I tried to extend it and well it did not work.
Example Usage
$easyCMS->iterate($post,
echo $content[0];
echo $content[1];
);
Class Function
public function iterate($d,$fn){
$this->item = $d;
foreach($this->item as $post){
echo $fn;
}
}
Current Index.php Usage
$post = $easyCMS->my_query('SELECT * FROM `newsPost`');
//returns array
$easyCMS->iterate($post,
$content[0]."<br>",
$content[1]."<br>",
$content[2]."<br>",
$content[3]."<br>",
$content[4]."<br>",
);
//$post would be the first argument and after that would be what we want our function to do.
I get the error =>
Parse error: syntax error, unexpected ';' in .../index.php on line 23
Which I know that it's the constant $content[num] but I'd like to know how I'd do this for I know I could with JavaScript using the call method.
My database table looks something like
id: 1 == content: "Whats up" == ...etc
I want my code to iterate over these so then I can write like so
$easyCMS->iterate($post,
'<div class="hello">'.$content[0].'</div><div id="post_'.$content[1].'"><div class="content">'.$content[2].'</div>'
);
the error is caused by:
$easyCMS->iterate($post,
$content[0]."<br>";
$content[1]."<br>";
$content[2]."<br>";
$content[3]."<br>";
$content[4]."<br>";
);
which should be
$easyCMS->iterate($post,
$content[0]."<br>",
$content[1]."<br>",
$content[2]."<br>",
$content[3]."<br>",
$content[4]."<br>"
);
i don't think that this code solves your needs
Here is the best way for an easy iterator, took me some time but I finally solved it.
Class Function
public function iterate($d,$fn){
foreach($d as $item){
$txt = str_replace('{author}',$item["author"],$fn);
$txt = str_replace('{id}',$item["id"],$txt );
$txt = str_replace('{content}',$item["content"],$txt);
$txt = str_replace('{date}',$item["date"],$txt);
echo $txt;
}
}
PHP page IE index.php
$post = $easyCMS->my_query('SELECT * FROM `newsPost`');
$easyCMS->iterate($post,'<div class="hello">{author}</div><div id="post_{id}"><div class="content">{content}</div></div>');
$easyCMS->my_query is just a regular query which returns specific information
my_query
public function my_query($sql)
{
$array=array();//add an array
$query = mysqli_query($this->connect,$sql);
if($query > 0){
$c = mysqli_num_rows($query);//get how many rows there are
if($c > 1){//if greater than one push into the array
while($fetch = mysqli_fetch_array($query)){//while loop to push
array_push($array, $fetch);
}
return $array;
}else{
return mysqli_fetch_row($query);//rows is only one
}
}else{
return "No such query";//if the query does not exist!
}
}
Can't help but think you're over-complicating things here.
If you're using an array without an index key then it would be as simple as:
public function iterate($d,$fn){
foreach($d as $content){
echo $content;
}
}
Only if an index is key=>pair do you need to it like:
foreach ($d as $key=>$value) {
stuff//
}
$easyCMS->iterate($post,
'<div class="hello">'.$content[0].'</div>
<div id="post_'.$content[1].'"><div class="content">'.$content[2].'</div>'
);
Is wrong. When using " and ', you want to wrap ' inside of the ".
If, what you want is to irerate through a loop inside a loop, you'd want something like:
Foreach($post as $pos) {
$class->some_func($pos);
}
public function some_func ($post) {
/formatting.
echo $post;
/formatting.
}
The simplest I can come up with, based on your code currently is:
foreach($stuff_from_database_call as $content)
echo "formatting stuff". $content . "/close formatting";
Technically you could 1 line it, so long as dont mind using . to join strings :)
Note the lack of [0] [1] etc, which is un-needed, since you are iterating through the array. However, if it was a key=>pair you'd do it like this:
foreach($stuff_from_database_call as $key=>$content)
echo "formatting stuff". $key[$content] . "/close formatting";
Updated this after you wrote out and accepted your own answer. Instead of:
public function iterate($d,$fn){
foreach($d as $item){
$txt = str_replace('{author}',$item["author"],$fn);
$txt = str_replace('{id}',$item["id"],$txt );
$txt = str_replace('{content}',$item["content"],$txt);
$txt = str_replace('{date}',$item["date"],$txt);
echo $txt;
}
}
I'd suggest something more like:
public function iterate($d,$fn){
foreach($d as $item=>$value){
$txt = str_replace('{$value}',$item[$value],$fn);
echo $txt;
}
}
This will make it a LOT more flexible, as you can easily add fields, without having to touch the function itself. When coding, ALWAYS try and do so with as much forethought as you can, so you save yourself headaches down the road.
Either way, glad you got it sorted, and glad you came back to post your sollution.
1 last afterthought. Try naming your variables a little more reader friendly :) $d is nowhere near descriptive enough. Just another avoidable headache, for yourself and for anyone else having to look at your code :)