Robbat2 (robbat2) wrote,

Terrible PHP hacks: making PHP/FI style file uploads work in PHP5.5 and newer

One of my past consulting customers, came to me with a problem. He'd been relatively diligent in upgrading his servers since last I spoke (it had been some years), and now the admin panel on one of his client's very old PHP websites was no longer working.

I knew the code had some roots back to at least PHP3, at the file headers I'd previously seen had copyright dates back to 1999. Little did I know, I was in for a treat today.

When last I visited this codebase, due to it's terrible nature with hundreds of globals, I had to put some hacks in for PHP 5.4, since register_globals were no longer an option. The hack for this is quite simple:

foreach($_POST as $__k => $__v) { $$__k = $__v; }
foreach($_GET as $__k => $__v) { $$__k = $__v; }

Well it seems since the last upgrade, they had also changed the register_long_arrays setting by demand of another project, and the login on the old site was broken. Quite simple this, just need to s/HTTP_SERVER_VARS/_SERVER/ (and similarly for POST/GET/COOKIE depending on your site).

Almost all was well now, except that the next complain was file uploads didn't work for several forms. I naively duplicated the _POST/_GET block above to $_FILES. No luck. Thus, my memory not remembering how file uploads used to work in early PHP, I set out to fix this.

I picked a good one to test with, and noticed that it used some of the very old PHP variables for file uploads (again globals). These files dated back to 1997 and PHP/FI!. The initial solution was to map $_FILES[x]['tmp_name'] to $x, and the rest of $_FILES[x][y] to $x_y. Great it seems to work now.

Except... one file upload form was still broken; it had multiple files allowed in a single form. Time for a more advanced hack:

# PHP/FI used this structure for files:
foreach($_FILES as $__k => $__v) { 
  if(!is_array($__v['tmp_name'])) {
    $s = $__k;
    $$s = $__v['tmp_name'];
    $keys = array('name','size','type');
    foreach($keys as $k) {
      $s = $__k.'_'.$k;
      $$s = $__v[$k];
  } else {
    for($i = 0; $i <= count($__v['tmp_name']); $i++) {
      if(defined($__v['tmp_name']) && defined($__v['tmp_name'][$i])) {
        $s = $__k.'['.$i.']';
        $$s = $__v['tmp_name'][$i];
        $keys = array('name','size','type');
        foreach($keys as $k) {
          $s = $__k.'_'.$k.'['.$i.']';
          $$s = $__v[$k][$i];

Thus I solved the problem, and had to relearn back how it used to be done with PHP/FI.

Tags: old code, php
  • Post a new comment


    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded