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

投稿

PHPのXMLReaderを使ったXMLの読み込み

はじめに PHPでXMLを読み込むには、通常はSimpleXMLElementを使えば十分です。 ただし、XMLが巨大でメモリを節約して処理する必要がある場合は、XMLのパーサーであるXMLReaderを使って処理する方法があります。 XMLReaderを使って読み込む際はXMLの構造をどうとらえるかによって、プログラムの書き方が変わるのと、毎回読み込みの方法をプログラムしなければならないのが欠点です。 今回は下記のサンプルXMLのproduct部分を読み込むXMLReaderのプログラムのサンプルを、XMLReaderの機能紹介も兼ねて、いくつか示します。 <?xml version="1.0" encoding="UTF-8"?> <products> <date type="1">20200414</date> <product> <maker>AMD</maker> <name>Ryzen 3400G</name> </product> <product> <maker>Intel</maker> <name>Core i9 9900K</name> </product> </products> サンプルプログラムでは、下記のPHPの配列形式を取得することを目標にします。 実際の用途ではXMLReaderを使ってXMLを読み込むと同時に、CSVファイルに出力するなどといった処理が考えられます。 この場合、メモリはXMLReader部分と、読み込み途中で一時的に保持しているデータのみで利用されるので、メモリの使用量は最低限に抑えることができます。 [ [ "maker"=> "AMD", "name"=> "Ryzen

PHPで与えられた配列の次元数を取得する方法

PHPの多次元配列で次元数を推定する関数の紹介です。 [注意] 配列の最初の要素だけをチェックしていくので、すべての配列の次元が同じであること前提としています。 そもそも配列の次元数がバラバラ(C#でいうjagged array)であれば、今回紹介する関数は使えません。 <?php function getDimension(array $source) { if(is_array($source)) { return getDimension(reset($source)) + 1; } else { return 0; } } // 下記のような配列を引数で与えます。 $source[1]['A']['a'] = true; $source[2]['B']['a'] = true; $source[3]['A']['a'] = true; $source[4]['B']['a'] = true; // 結果は3になります。 getDimension($source);

PHPで空のディレクトリを再帰的にすべてたたどるプログラム

PHPで指定したディレクトリにある全ディレクトリ内の空ディレクトリをすべてたどるプログラムを書いてみました。 書いた動機としては、あるディレクトリ内にあるディレクトリをすべて削除したかったためです。 symbolic linkはファイルとして扱っているので無視されます。 <?php // $callbackの引数の$fileに、空ディレクトリの\SplFileInfoが渡されて呼ばれます。 function visitEmptyDirectoryRecursively($path, callable $callback) { $files = new \DirectoryIterator($path); $containsOnlyDirectory = true; /* @var $file \SplFileInfo */ foreach($files as $file) { if($file->isDot()) { continue; } else if($file->isDir()) { if(visitEmptyDirectoryRecursively($file->getRealPath(), $callback)) { $callback($file); } else { $containsOnlyDirectory = false; } } else { $containsOnlyDirectory = false; } } return $containsOnlyDirectory; } // 空ディレクトリをすべて削除する場合は、下記のようにして使います。 // permissionの関係でディレクトリを消すことができないなどのエラー処理が必要な場合は、

SQLで特定の文字を組み合わせたランダムな文字列を生成

簡易的な方法として「指定した文字列からランダムに1文字選ぶ」を必要な文字の長さ分concat関数でつなげれば実現できます。 1文字ずつ文字を選ぶので、あまり性能もよくない上、セキュリティ的な観点からのランダム性も担保されていないので、あくまで開発中に必要になった時に使う程度が無難だと思います。 下記に英数字大文字小文字を含んだランダムな3文字の文字列を生成するクエリを示します。 # RAND関数で指定した文字列からランダムに1文字選択。 # 下記の例の62の部分はa~z、A~Z、1~9の文字数の合計値を入れた結果 SELECT CONCAT( SUBSTRING('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', FLOOR(RAND() * 62 + 1), 1), SUBSTRING('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', FLOOR(RAND() * 62 + 1), 1), SUBSTRING('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', FLOOR(RAND() * 62 + 1), 1) ) AS random_string;

GitのCheckoutとCommitをするBashスクリプト

テキスト系のファイルをバックアップするために、Gitレポジトリを利用することがあるのですが、使いまわせるようにbashで簡単なスクリプトを書いてみました。 単純なバックアップ目的なので、branchは固定でmasterを指定しています。 #!/bin/bash checkout(){ local url=${1} local checkout_dir=${2} if [ ! -d $checkout_dir ] then git clone $url $checkout_dir else cd $checkout_dir git pull fi } commit(){ local commit_target_dir=${1} local message=${2} cd $commit_target_dir diff_count=$(echo `git status -s | wc -l`) if [ $diff_count -ne 0 ]; then git add -A git commit -m $message git push origin master fi } ### 使用例 ### USER=... PASSWORD=... # URL組み立て URL=https://$USER:$PASSWORD@githost/project checkout $URL "backup_directory" ### do something in backup_directory... commit "backup_directory" "Auto commit by bash" ちなみに筆者は、バックアップを下記の手順で取ってgitへ入れています。参考になれば、、、 上記のcheckout関数を用いて、gitレポジトリからプロジェクトをclone(既にclone済みの場合はpull) リモートホストからチェックアウトしたディレクトリへファイルをrsyncで同期 上記のcommit関数を用いて、gitレポジトリへpush

PHPでCSV形式でデータを出力するためのコード

PHPでCSVファイルを出力するためのコードサンプルです。 CsvWriterクラスが本体です。最低限のメソッドを定義してあるだけなので必要に応じて拡張してみてください。 Writerインタフェースを定義して、CsvWriterクラスのコンストラクタに渡して切り替えることで、出力方式を変更することができます。 CsvWriterクラス CSV形式で出力するための本体のクラスです。このクラスのコンストラクタにWriterインタフェースを実装したクラスを渡します。 <?php class CsvWriter { private Writer $writer; private $elements = []; public function __construct(Writer $writer) { $this->writer = $writer; } public function init() { $this->writer->init(); } public function appendValuesBySpecificOrder(array $values, $keys) { foreach ($keys as $key) { $this->appendEscaped($values[$key] ?? $default); } return $this; } public function appendValues(array $values) { foreach ($values as $value) { $this->appendEscaped($value); } return $this; } public function appendAsLine(array $values) { foreac

PHPでファイルを1行ごと読み込むためのIterator

タイトル通り、PHPでファイルを1行ごと読み込むためのIteratorをSplFileObjectを使って実装してみました。 <?php class TextFileRowIterator implements \Iterator { private ?\SplFileObject $file; private $filePath; private $current; private $lineNumber = 0; public function __construct($filePath) { $this->filePath = $filePath; } public function current() { return $this->current; } public function key(): \scalar { return $this->lineNumber; } public function next(): void { $this->lineNumber++; // 応用例として、SplFileObjectの呼び出すメソッドを、fgetcsvに変えるとcsvファイルを1行ごと配列で読み込むことができます。 $this->current = str_replace(["\r", "\n"], '', $this->file->fgets()); } public function rewind(): void { $this->file = null; $this->file = new \SplFileObject($this->filePath); $this->lineNumber = 0; if(!$this->file->eof()) { $this-&g