Feb 08

JSONJSON, or JavaScript Object Notation, is fairly popular.
This is just my modest take on a ‘PHP Object Notation’ implementation.
Note that it is meant to follow how your mind works rather than being syntactically correct; therefore, associative arrays are used in a loose manner where you have to worry about associative syntax as little as possible.
Basically, type away until your object is fully described.

Here is a notation sample:

PHP
  1.         ‘root level’ => array(
  2.                 ’sublevel 1′ => array(
  3.                         ’sublevel 2′ => ’sublevel 3′,
  4.                 ),
  5.         )
  6. );

.
This syntax can then be used the same way JSON is used, using eval. Here is how and you will immediately notice how the eval() syntax has to differ from the JavaScript one:

PHP
  1. $remote_str = <<<EOB
  2.     array(
  3.         ‘root level’ => array(
  4.                 ’sublevel 1′ => array(
  5.                         ’sublevel 2′ => ’sublevel 3′,
  6.                 ),
  7.         )
  8. );
  9. EOB;
  10. // …
  11. eval(‘$local_str=’.$remote_str.‘;’);

.
Feels a bit clumsy. Fortunately, starting with PHP4, if you are not too sad about introducing a statement in your remote string, you can rewrite it like this:

PHP
  1. $remote_str = <<<EOB
  2. return array(
  3.         ‘root level’ => array(
  4.                 ’sublevel 1′ => array(
  5.                         ’sublevel 2′ => ’sublevel 3′,
  6.                 ),
  7.         )
  8. );
  9. EOB;
  10. // …
  11. $local_str = eval($remote_str);

.
Better, isn’t it?

In this last listing, you will find the very simple code I wrote to traverse the object. Note that I invoke a callback for every element, otherwise this code would not be very helpful.

Note that this is just a concept for something I needed to throw together quickly therefore there are some limitations; for instance, you cannot have numeric keys since in this context their “keyness” is ignored and even feared.

PHP
  1. <?php
  2. function traverse_tree($callback, $curlevel, $curdepth, $uid)
  3. {
  4.         $depthstr = ‘——————————————————————————’;
  5.         $padding = substr($depthstr, 0, $curdepth);
  6.         if(!is_array($curlevel))
  7.         {
  8.                 $callback($curlevel, $padding, $uid);
  9.                 return;
  10.         }
  11.         foreach($curlevel as $level=>$children)
  12.         {
  13.                 if(!is_numeric($level))
  14.                 {
  15.                         $my_uid = $callback($level, $padding, $uid);
  16.                         traverse_tree($callback, $children, $curdepth + 2, $my_uid);
  17.                 }
  18.                 else
  19.                 {
  20.                         $callback($children, $padding, $uid);
  21.                 }
  22.         }
  23. }
  24.  
  25. function do_something($name, $padding, $uid)
  26. {
  27.         $iid = 0; // Bogus value
  28.         print $padding.$name." ($iid)\n";
  29.         return $iid;
  30. }
  31.  
  32. // ———————————————————–
  33. // Here we go
  34. // ———————————————————–
  35. if(count($argv) != 2)
  36.         die("\nSyntax: ".$PHP_SELF." ‘root_node_name’\n\n");
  37. $rootnodename = &$argv[1];
  38.  
  39. $INS = array(
  40.         $rootnodename => array(
  41.                 ‘Bikes’ => array(
  42.                         ‘Yamaha’ => ‘Fz’,
  43.                         ‘Honda’,
  44.                         ‘Norton’
  45.                         ),
  46.                 ‘Trikes’,
  47.                 ‘Cars’ => array(
  48.                         ‘Chevrolet’ => array(
  49.                                 ‘Corvette’ => array(‘Z06′, ‘Convertible’, ‘Coupe’),
  50.                                 ‘Camaro’,
  51.                                 ‘Jimmy’
  52.                                 ),
  53.                         ‘Ford’ => array(
  54.                                 ‘Mustang’ => array(‘GT’, ‘Premium’, ‘Shelby’, ‘Other’=>‘Roush’),
  55.                                 ‘Explorer’,
  56.                                 ‘Crown Victoria’
  57.                                 ),
  58.                         ‘Chrysler’ => array(
  59.                                 ‘Dodge’ => ‘Charger’,
  60.                                 ‘300X’,
  61.                                 ‘Le Baron’
  62.                                 ),
  63.                         )
  64.         )
  65. );
  66.  
  67. traverse_tree(do_something, $INS, 0, 1);
  68.  
  69. print "DONE\n\n";
  70. ?>

.
Invoke with:

  1. php my_php_script.php "Vehicles"

.
“What is this $iid variable?” you may ask.
You will notice that this piece of code is particularly convenient if you want to add a whole tree structure to your database. Say the you are using MySQL and want to create categories and sub-categories, using the column ‘pid’ as a category’s parent id. You would rewrite do_something:

PHP
  1. function do_something($name, $padding, $uid)
  2. {
  3.         mysql_query("INSERT INTO my_cat_table(pid, title) VALUES({$uid}, ‘{$name}’)");
  4.         $iid = mysql_insert_id();
  5.         print $padding.$name." ($iid)\n";
  6.         return $iid;
  7. }

Voila!

Sphere: Related Content

Dec 26

SQLEvery now and then, a developer makes a post on their blog that, to the unsuspecting novice, seems like common sense.
Beware, though. If the post is less than comprehensive or accurate, it better not be about security matters or that newly acquired peace of mince may be quickly shattered.

Exhibit A: This post on the topic of PHP and SQL injections. It’s not like there is a lack of information already freely available on the web.
The author even references this excellent material at the end of his post. It is too bad that his own article actually contains less relevant information than the original post.

For instance, he recommends the use of mysql_real_escape_string().

  • Observation #1: this implies that you are using mysql as your database of choice. Granted you may use this method before sending a SQL query to Postgresql, but then there is no guarantee that mysql functions were compiled in the current php library.
  • Observation #2: mysql_real_escape_string() does nothing more than escape quotes. From the original article: “Be aware that “sanitizing the input” doesn’t mean merely “remove the quotes”, because even “regular” characters can be troublesome.

He recommends validating for the proper input, which is good practice. So, brownie points for that. But it wouldn’t hurt to have, for instance, mentioned the use of intval() to enforce that integer values are nothing but that. Integer values. I would say that it’s advice just as important as escaping input strings.

Now, the part that I found horrifying, but it’s just me, I’m a stickler: the author encourages you to code your HTML forms so that they will not accept too many characters. I see here some confusion: this is good usability advice, granted, but as far as security it is misguided.

The golden rule is simple: Always perform input validation server-side, where the user cannot ‘fake’ the values they are sending to your application.
Never, ever accept data “as-is” if it came through a path that allowed it to be tampered with.

Two other equally important points I wish he had mentioned are:

  • Configure error reporting so that your server does not display these “helpful” error messages that he mentions and attackers are delighted to find
  • A good SQL query is one cautiously put together, but a great SQL query relies on prepared statements. There are cases when you are after raw speed and direct queries feel more ‘natural’ -I know, I use them a lot- but whenever possible, use prepared statements, since the user is then not given a chance to “write” your query string himself.
Sphere: Related Content