Jörg Reinholz: Das Skript zum Sonntag - PHP-Skripte automatisch reparieren

Beitrag lesen

Moin!

Immer wieder bekomme ich Anfragen, dass bestimmte PHP-Skripte nur eine "leere Seite" liefern. Grund ist meist, dass der Verwender diese in einem Windows-Editor (deshalb auch unter "Barrierefreiheit" "getackert") geöffnet hatte (der dann prompt eine BOM hineinschrieb) oder Leerzeichen bzw. Leerzeilen "hineingepfuscht" hat, was dann bei einem Aufruf von header() nicht mit einer Fehlermeldung quittiert wird ...

Dieses Skript repariert Einiges davon:

<?php
## repariert PHP Skripte:
## entfernt BOMs
## entfernt Leerzeilen am Beginn
## entfernt Leerzeichen vor <? oder <?php 
## ersetzt <? durch <?php

# Konfiguration:

$config['DIR'] = '/tmp';   # In welchem Verzeichnis sollen die Dateien repariert werden?
#$config['DIR'] = '.';     # aktuelles Verzeichnis
#$config['DIR'] = __DIR__; # Verzeichnis dieses Skriptes
#$config['DIR'] = $SERVER['DOCUMENT_ROOT'];

$config['IGNOREUPPERLOWER'] = false; # Für Linux-Benutzer...
#$config['IGNOREUPPERLOWER'] = true; # Für Windows-Benutzer...

$config['FIND'] = '*.inc.php'; # * beliebiges Zeichen beliebig oft
                           # ? beliebiges Zeichen genau einmal

$arExkludeList=array(
    # Nach letztem Eintrag kein Komma!
    'diese_nicht/*', # Unterverzeichnis ausgehend von $config['DIR'], kein führender "/"
    '*.ex'    # Dateien mit Endung "ex"
);

$habeBackup = false; # Setzen Sie dieses aus true, nachdem ein Backup gemacht wurde.

## Ab hier ändern nur Programmierer, die wissen, was sie tun:

define ( 'DIR', rtrim($config['DIR']), '/' );
define ( 'FIND', $config['FIND'] );
define ( 'IGNOREUPPERLOWER', $config['IGNOREUPPERLOWER']);

if ( isset($SERVER['DOCUMENT_ROOT']) ) {
    define ('NL', "<br>\n");
} else {
    define ('NL', "\n");
}

$fileList=getFileList(DIR);
$arExkludeListRegex=array();

foreach ($arExkludeList as $s) {
   if ($s) {
        $arExkludeListRegex[] = patternToRegex(DIR . '/' . $s, true, IGNOREUPPERLOWER);
   }
}
unset($arExkludeList);

foreach ($fileList as $file) {
    $isExcluded=false;
    foreach ($arExkludeListRegex as $regex) {
        if ( ! $isExcluded && preg_match($regex, $file)  ) {
           $isExcluded=true;
           break;
        }
    }

    if ($isExcluded) {
        echo "Info: '$file' wurde ausgeschlossen.", NL;
    } elseif (! is_readable($file)) {
        echo "Warnung: Keine Leserechte an '$file'", NL;
    } elseif (! is_writable($file)) {
        echo "Warnung: Keine Schreibrechte an '$file'", NL;
    } elseif ($habeBackup) {
        echo "Info: Verarbeite '$file'";
        repair($file);
    } else {
        echo "Info: würde '$file' verarbeiten, wenn das Anlegen eines Backups bestätigt wäre.", NL;
    }
}

echo "### Fertig! ###", NL;

#### Von diesem Skript verwendete Funktionen ####
# sollten unverändert bleiben.

function patternToRegex($string, $allRow=false, $ignoreUpperLower=false) {
    if ($ignoreUpperLower) {
        $ignoreUpperLower='i';
    } else {
        $ignoreUpperLower='';
    }

    $string=str_replace('/', '\\/', $string);

    $search  = array( '.' , '*' , '?');
    $replacment = array( '\.', '.*', '.');

    if ($allRow) {
        return '/^' . str_replace($search, $replacment,  $string) . '$/' . $ignoreUpperLower;
    } else {
        return '/' . str_replace($search, $replacment,  $string) . '/' . $ignoreUpperLower;
    }
}

function getFileList($dir) {
    $list=array();
    $regex = patternToRegex(FIND, false, IGNOREUPPERLOWER);
    if ( is_dir($dir) && is_readable($dir) ) {
        $d = dir($dir);
        if ($d) {
            while (false !== ($entry = $d->read())) {
                if ( '.' != $entry && '..' != $entry ) {
                    $entry = $dir .'/'. $entry;
                    if ( is_dir($entry) ) {
                        $arT = getFileList($entry);
                        foreach ($arT as $s) {
                            $list[]=$s;
                        }
                    } elseif ( preg_match($regex, $entry) ) {
                        $list[] = $entry;
    }   }   }   }   }
    return $list;
}


#### Arbeitende Funktionen ####
# können für andere Verwendungen ersetzt werden

function repair($file) {
    $newSkript = '';
    $isFirstLine = true;

    $ar=file($file);

    foreach ($ar as $row) {
        #$row = trim($row);
        $row = rmBOM($row);                      #löscht alle bekannten BOM
        if ( $isFirstLine ) {
            $row = rmOnlySpaces($row);           #löscht alle Spaces in Zeilen, die nur solche
                                                 #enthalten 
        }
        if ( $row ) {
            $row = rmSpacesBevorPhpTag($row);    #löscht alle spaces vor <?php
                                                 #ersetzt <? und <?PHP durch <?php
            $newSkript .= $row;
            $isFirstLine = false;
        }
    }
    file_put_contents($file, $newSkript);
    echo " ... erledigt!", NL;
}


function rmBOM($str, $replacment = '') {
 # source: https://en.wikipedia.org/wiki/Byte_order_mark

    $boms=array(
        urldecode('%EF%BB%BF'),       #UTF-8
        urldecode('%FE%FF'),          #UTF-16 (BE)
        urldecode('%FF%FE'),          #UTF-16 (LE)
        urldecode('%00%00%FE%FF'),    #UTF-32 (BE)
        urldecode('%FF%FE%00%00'),    #UTF-32 (LE)
        urldecode('%2B%2F%76%38'),    #UTF-7
        urldecode('%2B%2F%76%39'),    #UTF-7
        urldecode('%2B%2F%76%2B'),    #UTF-7rmOnlySpaces
        urldecode('%2B%2F%76%2F'),    #UTF-7
        urldecode('%2B%2F%76%38%2D'), #UTF-7
        urldecode('%F7%64%4C'),       #UTF-1rmOnlySpaces
        urldecode('%DD%73%66%73'),    #UTF-EeBCDIC
        urldecode('%0E%FE%FF'),       #SCSU
        urldecode('%FB%EE%28'),       #BOCU-1
        urldecode('%84%31%95%33')     #GB-18030
    );
    return str_replace($boms, $replacment, $str);
}

function rmSpacesBevorPhpTag($str, $replacment = '') {
    $replacment .= '<?php';
    return preg_replace('/^\s*<\?([pP][hH][pP]){0,1}/', $replacment, $str);
}

function rmOnlySpaces($str, $replacment = 'repair($file)') {
    return preg_replace('/^\s+$/', $replacment, $str);
}

Jörg Reinholz