しかし、これらの「未定義の変数」警告をすべて取り除くためのより良い解決策を知っていれば、私の一日を過ごすことができます.
がある。スーパーグローバルが使用されていない問題を修正します。もちろん、フリッピング変数の呼び出しをすべて自分で手動で変更する必要があると言っているわけではありませんが、これはおそらく自動化できるものだと思います。私の脳波を追跡できるかどうかを確認してください。
まず、すべての「未定義変数」通知のリストを取得する必要があります。これは、エラー ハンドラを登録し、E_NOTICE 呼び出しをチェックし、それが未定義の変数呼び出しかどうかをチェックするのと同じくらい簡単です。私は自由に、まさにそれを行う小さなコードを書き上げました。
<?php
/**
* GlobalsLog is a class which can be used to set an error handler which will
* check for undefined variables and checks whether they exist in superglobals.
*
* @author Berry Langerak
*/
class GlobalsLog {
/**
* Contains an array of all undefined variables which *are* present in one of the superglobals.
*
* @var array
*/
protected $globals;
/**
* This contains the order in which to test for presence in the superglobals.
*
* @var array
*/
protected $order = array( 'SERVER', 'COOKIE', 'POST', 'GET', 'ENV' );
/**
* This is where the undefined variables should be stored in, so we can replace them later.
*
* @var string
*/
protected $logfile;
/**
* Construct the logger. All undefined variables which are present in one of the superglobals will be stored in $logfile.
*
* @param string $logfile
*/
public function __construct( $logfile ) {
$this->logfile = $logfile;
set_error_handler( array( $this, 'errorHandler' ), E_NOTICE );
}
/**
* The error handler.
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @return boolean
*/
public function errorHandler( $errno, $errstr, $errfile, $errline ) {
$matches = array( );
if( preg_match( '~^Undefined variable: (.+)$~', $errstr, $matches ) !== 0 ) {
foreach( $this->order as $superglobal ) {
if( $this->hasSuperglobal( $superglobal, $matches[1] ) ) {
$this->globals[$errfile][] = array( $matches[1], $superglobal, $errline );
return true;
}
}
}
}
/**
* Called upon destruction of the object, and writes the undefined variables to the logfile.
*/
public function __destruct( ) {
$globals = array_merge( $this->globals, $this->existing( ) );
file_put_contents(
$this->logfile,
sprintf( "<?php\nreturn %s;\n", var_export( $globals, true ) )
);
}
/**
* Gets the undefined variables that were previously discovered, if any.
*
* @return array
*/
protected function existing( ) {
if( file_exists( $this->logfile ) ) {
$globals = require $this->logfile;
return $globals;
}
return array( );
}
/**
* Checks to see if the variable $index exists in the superglobal $superglobal.
*
* @param string $superglobal
* @param string $index
* @return bool
*/
protected function hasSuperglobal( $superglobal, $index ) {
return array_key_exists( $index, $this->getSuperglobal( $superglobal ) );
}
/**
* Returns the value of the superglobal. This has to be done on each undefined variable, because
* the session superglobal maybe created *after* GlobalsLogger has been created.
*
* @param string $superglobal
* @return array
*/
protected function getSuperglobal( $superglobal ) {
$globals = array(
'SERVER' => $_SERVER,
'COOKIE' => $_COOKIE,
'POST' => $_POST,
'GET' => $_GET,
'ENV' => $_ENV
);
return isset( $globals[$superglobal] ) ? $globals[$superglobal] : array( );
}
}
/**
* Lastly, instantiate the object, and store all undefined variables that exist
* in one of the superglobals in a file called "undefined.php", in the same
* directory as this file.
*/
$globalslog = new GlobalsLog( __DIR__ . '/undefined.php' );
要求された各ページにこのファイルを含める場合 (オプションで を使用php_prepend_file
)、アプリケーション全体をクリックした後、すべての未定義変数が「undefined.php」に含まれることになります。
これはかなり興味深い情報です。未定義の変数がどのファイル、どの行、どのスーパーグローバルに実際に存在するかがわかったからです。スーパーグローバルを決定するとき、優先順位を決定するために、Environment、Get、Post、Cookie、および Server の順序を念頭に置きました。
巧妙な小さなトリックの次の部分では、notice が見つかったすべてのファイルをループしてundefined variable
、未定義の変数を対応するスーパーグローバル変数に置き換えようとします。これも実際には非常に簡単です。繰り返しますが、そのためのスクリプトを作成しました。
#!/usr/bin/php
<?php
/**
* A simple script to replace non globals with their globals counterpart.
*/
$script = array_shift( $argv );
$logfile = array_shift( $argv );
$backup = array_shift( $argv ) === '--backup';
if( $logfile === false || !is_file( $logfile ) || !is_readable( $logfile ) ) {
print "Usage: php $script <logfile> [--backup].\n";
exit;
}
$globals = require $logfile;
if( !is_array( $globals ) || count( $globals ) === 0 ) {
print "No superglobals missing found, nothing to do here.\n";
exit;
}
$replaced = 0;
/**
* So we have the files where superglobals are missing, but shouldn't be.
* Loop through the files.
*/
foreach( $globals as $filename => $variables ) {
if( !is_file( $filename ) || !is_writable( $filename ) ) {
print "Can't write to file $filename.\n";
exit;
}
foreach( $variables as $variable ) {
$lines[$variable[2]] = $variable;
}
/**
* We can write to the file. Read it in, line by line,
* and see if there's anything to do on that line.
*/
$fp = fopen( $filename, 'rw+' );
$i = 0;
$buffer = '';
while( $line = fgets( $fp, 1000 ) ) {
++$i;
if( array_key_exists( $i, $lines ) ) {
$search = sprintf( '$%s', $lines[$i][0] );
$replace = sprintf( "\$_%s['%s']", $lines[$i][1], $lines[$i][0] );
$line = str_replace( $search, $replace, $line );
$replaced ++;
}
$buffer .= $line;
}
if( $backup ) {
$backupfile = $filename . '.bck';
file_put_contents( $backupfile, file_get_contents( $filename ) );
}
file_put_contents( $filename, $buffer );
}
echo "Executed $replaced replacements.\n";
unlink( $logfile );
あとは、このスクリプトを呼び出すだけです。私はこれをテストしました。これは私がテストしたファイルです:
<?php
require 'logger.php';
$_GET['foo'] = 'This is a value';
$_POST['foo'] = 'This is a value';
$_GET['bar'] = 'test';
function foo( ) {
echo $foo;
}
foo( );
echo $bar;
2 つの未定義変数 ($foo
および$bar
) があり、どちらも 1 つ (または複数) のスーパーグローバルに存在します。ブラウザでページにアクセスした後、ログファイルに 2 つのエントリがありましたundefined.php
。つまり、foo と bar です。次に、コマンドを実行するphp globalsfix.php undefined.php --backup
と、次の出力が得られました。
berry@berry-pc:/www/public/globalfix% php globalsfix.php undefined.php --backup
Executed 2 replacements.
結果がどうなったか知りたいですか?私もそうでした。
<?php
require 'logger.php';
$_GET['foo'] = 'This is a value';
$_POST['foo'] = 'This is a value';
$_GET['bar'] = 'test';
function foo( ) {
echo $_POST['foo'];
}
foo( );
echo $_GET['bar'];
万歳!未定義の変数はもうありません。これらは現在、正しいスーパーグローバルから読み取られています。大きな免責事項:最初にバックアップを作成してください。また、これですべての問題がすぐに解決されるわけではありません。ステートメントがある場合if( $foo )
、未定義の変数は、対応するブロックが実行されないようにします。つまり、すべての未定義の変数が一度にキャッチされるわけではありません (ただし、このスクリプトを使用すると、2 回目または 3 回目の実行でその問題が解決されます)。 . それにもかかわらず; コードベースの「クリーンアップ」を開始するのに適した場所です。
また、私の回答全体を読んでおめでとうございます。:)