スキップしてメイン コンテンツに移動

投稿

MySQLでデータサイズを確認する方法

MySQLでテーブルごとのデータサイズは、information_schemaから確認できます。 下記は、テーブルごとのデータサイズとインデックスサイズの合計を取得するためのクエリ例です。 SELECT table_schema, table_name, ROUND((data_length + index_length) / 1024 / 1024), 2) AS `MB` FROM information_schema.Tables ORDER BY (data_length + index_length) DESC;

PHPのXMLReaderで発生したエラーをExceptionとしてキャッチする方法

PHPのXMLReaderの内部で発生したエラーは、Exceptionではないためtry~catchブロックで捕まえることができません。 Exceptionとして捕まえるためには、set_error_handlerを使って、自前でエラーをExceptionに変換して投げる必要があります。 下記のコードで実現できます。 <?php // operationにエラーを発生させる可能性のある処理ブロックを渡す。 function caputureNativeErrorAndThrowIt(callable $operation) { $errorReportingLevel = error_reporting(E_ALL); set_error_handler(function( int $serverity, string $message, string $file, int $line ): void{ throw new \ErrorException($message, 0, $serverity, $file, $line); }); try { $operation(); } finally { restore_error_handler(); error_reporting($errorReportingLevel); } } // 下記はcaputureNativeErrorAndThrowIt関数をXMLReaderで使用した場合の例です。 $path = 'path_to_invalid_xml_file'; $reader = new \XMLReader(); $reader->open($path); caputureNativeErrorAndThrowIt(function() use($reader){ try { while($reader->read()){ // do something } } finally{ $reader->close()

PHPで特定の時刻の差分を秒数で計算するプログラム

PHPで特定の時刻の差分を秒数で計算する方法は、いろいろ考えられますが、ここではDateTimeクラスを使った方法を紹介します。 <?php // $date1, $date2はDateTimeで受け入れられる時刻の文字列表現であればOKです。 function diffSeconds(string $date1, string $date2) { return (new DateTime($date1))->getTimestamp() - (new DateTime($date2))->getTimestamp(); } // 下記のようにして使います。 diffSeconds('2020-06-05 13:54:32', '2020-04-21 22:12:22');

PHPでメモリにバッファしながらファイルに書き込む方法

最近のディスクは高速なのであまりIO Waitを意識することは少なくなりましたが、書き込み速度の遅いディスク(書き込みのコマンドのコストが高い)に何度も書き込みを実行すると、書き込みのトータルの時間が長くなる場合があります。 この投稿では、PHP版の簡単な「なんちゃって」BufferedWriterクラスを書いてみました。 通常であれば単純にfile_put_contentsメソッドを使って下記のように書けば十分です。 file_put_contents($filename, $chunk, FILE_APPEND|LOCK_EX); しかし、大量のデータを何度も書き込む場合に、特にパフォーマンスの観点から下記の問題が出てきます。 file_put_contentsはfopenによるファイルオープン、書き込み、クローズを実行するので手軽ではありますが、書き込みのオーバーヘッドは高くなります。 file_put_contentsに限ったことではないが、メモリにある程度バッファしてから書き込むことで、書き込みの実行回数を減らすことでパフォーマンスを高めることができる(例: JavaのBufferedWriter)。 というわけで、上記の問題を解決すべく、PHP版「なんちゃって」BufferedWriterクラスを書いてみました。 <?php class BufferedStreamFileWriter { private $path; private $bufferSize = 0; private $bufferLimit; private $buffer = ''; // constructor内でfopen public function __construct($path, $bufferLimit, $mode='a') { $this->path = $path; $this->bufferLimit = $bufferLimit; $this->handle = fopen($path, $mode); } // このメ

PHPのlibxmlでのエラーの扱い方

PHPでXML形式のデータを扱うにはlibxmlライブライを使うことが一般的です。 libxml内でのエラー発生時の処理は、libxml_use_internal_errorsの設定で、下記の2通りの設定が可能です。 libxml_use_internal_errors(false): Exceptionとして投げる。 libxml_use_internal_errors(true): libxml_get_errors()で取得。※libxml_clear_errorsで事前にエラーをクリアしておく方が無難。 libxml_use_internal_errors(true)に設定して、Exceptionを発生させないようにする関数のサンプルを示します。 $excecutionに実際のXML処理を渡します。 function executeInLibXmlUseInternalErrors(callable $execution) { // 現在のlibxml_use_internal_errorsの設定を処理後に戻すために保存 $useErrors = libxml_use_internal_errors(); try {   libxml_clear_errors(); libxml_use_internal_errors(true); return $execution(); } finally{ // 処理が終わったらlibxml_use_internal_errorsの設定をもとに戻す libxml_use_internal_errors($useErrors); } } // 下記はXPathでDOMDodumentからXMLの要素を取得する場合の使用例です。 // XMLの処理中にもExceptionが発生しないので、プログラム内で処理することができます。 $xpath = '/xpath'; $file = '/path_to_xml_file'; $result = executeInLibXmlUseInternalErrors(function

register_shutdown_functionを使ってPHPのFatal Error発生後の処理を制御

PHP 7以降では、PHPのエラーは基本的にErrorクラスとして扱われ、try-catchブロックで捕まえることができるようになりました。(Catchable Fatal Error) ちなみにPHP 7では下記の2つのクラスがThrowableクラスを継承しており、両方捕まえるときは、try-catchブロックでThrowableをcatchするように書けばOKです。 Exception Error ただし、一部のFatal Error(例: Memory Exhausted Error)はtry-catchブロックで捕まえることができません。 Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 9792 bytes) in .... この場合は、register_shutdown_functionを使って、PHPのプログラムが終了したときにエラー処理をするしかなさそうです。 register_shutdown_functionとerror_get_lastを使ってエラー処理をする関数のコード例を示します。 <?php // PHPのError定数 => 文字列表現の連想配列 const ERROR_CODE_TO_STRING = [ E_ERROR => 'E_ERROR', E_WARNING => 'E_WARNING', E_PARSE => 'E_PARSE', E_NOTICE => 'E_NOTICE', E_CORE_ERROR => 'E_CORE_ERROR', E_CORE_WARNING => 'E_CORE_WARNING', E_COMPILE_WARNING => 'E_COMPILE_WARNING', E_USER_ERROR => 'E_USER_ERROR', E_USER_WARNING => '

Linuxで特定のパターンにマッチするファイルの削除方法

Linuxで特定のパターンにマッチするファイルの削除方法について簡単にメモ 例1: /tmpディレクトリ配下の128bit hash(例:e111c876b32143abccd98bb56542bcc2)のパターンにマッチするファイルをすべて削除 regextypeを指定しないと我々が普段(?)よく知っているposixのregexが使えないことに注意! find /tmp -type f -regextype posix-egrep -regex '\./[0-9a-f]{32}' -delete 例2: /tmpディレクトリ配下の、AAAで始まるディレクトリで、更新日が5日以前のものを、ディレクトリの中身のファイルも含めてすべて削除 最後の「-exec {} +」は複数のファイルをまとめてコマンド実行するという意味 「-exec {} ;」の場合はファイル一個ずつの処理になるので、rmの場合は「-exec {} +」の方が効率が良い。 find /tmp -mindepth 1 -maxdepth -type d -mtime +5 -name ".AAA*" -exec rm -rf {} +