やったこと・書いたもの{2023,08-09}

8月分の内容を残し忘れていたのでまとめて・・

OSS

ペチコンの資料を作っていて、PHPマニュアルのちょっとした修正漏れに気付いたのでパッチを投げました。
@phpに貢献してみたいなぁ〜って思っていたので、嬉しいですね github.com

勉強会・LT

他社との合同クローズド勉強会

speakerdeck.com

その他

会社のブログ。

zenn.dev

zenn.dev

あのアカセさんにお誘いを受けて、またお邪魔してきましたの回 🙌

tsunagi.me

streamWrapperが「何文字読み込めるか」みたいなのを少し掘る

streamWrapperが〜みたいな記事をzennに書いたんですけども。 zenn.dev

記事中でも「多分こんな感じで動いてるけど、実装を見てないからわからないよ」と書いているのが、stream_readとファイル読み込みサイズの関係。

動かす

準備

例えば、「いつも決まった文字列(PHPスクリプトとして解釈可能)を返す」というstreamWrapperを用意する。
返すのは "<?php echo time() . PHP_EOL; ?>\n"; とし、これは読み取り文字数*1を無視して、いつも返すようにする。

<?php

class InvalidStreamWrapper
{
    private $content = "<?php echo time() . PHP_EOL; ?>\n";

    public function stream_read($count)
    {
        return $this->content;;
    }
}

毎回固定文字列を返すと、ファイル終端のハンドリングに失敗して無限ループが発生するので、「3回stream_read()を読んだら空データを返す」ようにする

<?php
class InvalidStreamWrapper
{
    private $counter = 0;

    public function stream_read($count)
    {
        if ($this->counter > 2) {
            return '';
        }
        $this->counter++;

        return $this->content;;
    }

その他、動作に最低限必要な stream_open()stream_eof()stream_set_option() をダミーで定義して、 return true; させておく。
また、stream_stat() も一旦 return true;で済ませる。

<?php
class InvalidStreamWrapper
{

    public function stream_stat()
    {
        return true;
    }

    public function stream_open($path, $mode, $options, &$opened_path): bool
    {
        return true;
    }

  public function stream_eof(): bool
    {
        return true;
    }

    public function stream_set_option($option, $arg1, $arg2)
    {
        return true;
    }
}

これを利用するための実行部分は以下

<?php

stream_wrapper_unregister('file');
stream_wrapper_register('file', InvalidStreamWrapper::class);

echo '========file_get_contents' . PHP_EOL;
echo file_get_contents('non-exists-file');
echo '========require' . PHP_EOL;
require 'non-exists-file';

3v4l.org

sizeの指定なしで動かす

で、実行するとこうなる

========file_get_contents
<?php echo time() . PHP_EOL; ?>
<?php echo time() . PHP_EOL; ?>
<?php echo time() . PHP_EOL; ?>
========require
1695457515
1695457515
1695457515

sizeの指定がない限り、file_get_content()requireも同様に「終端が来るまでファイルを読み込む」ように見える。
また、stream_eof()の結果も変わらない。

sizeの指定をして動かす

stream_stat() がsize情報を返すように改変する。
挙動をわかりやすくするために、ついでに実行部分もいじる。

<?php

echo 'fstat.size = ' . (fstat(fopen('non-exists-file', 'r'))['size']) . PHP_EOL;

class InvalidStreamWrapper
{

    private $size = 32;

    public function stream_stat()
    {
        return ['size' => $this->size];
    }
}

まずはsize=32で。これは、 strlen(IngalidStreamWrapper::$content)と一致する。

実行結果

fstat.size = 32
========file_get_contents
<?php echo time() . PHP_EOL; ?>
<?php echo time() . PHP_EOL; ?>
<?php echo time() . PHP_EOL; ?>
========require
1695458370

3v4l.org

「requireだと1回しか$contentが出力されていない」という形に。

sizeを増やしてみる

<?php
    private $size = 32 * 2;

すると、次の結果に

fstat.size = 64
========file_get_contents
<?php echo time() . PHP_EOL; ?>
<?php echo time() . PHP_EOL; ?>
<?php echo time() . PHP_EOL; ?>
========require
1695458351
1695458351

sizeが0の場合は、予想していた挙動と変わった。これは無指定時と同じになる

<?php
    private $size = 32 * 0;
fstat.size = 0
========file_get_contents
<?php echo time() . PHP_EOL; ?>
<?php echo time() . PHP_EOL; ?>
<?php echo time() . PHP_EOL; ?>
========require
1695458321
1695458321
1695458321

では、contenの長さと一致しないsizeにしてみるとどうなるか。
例えばsize=4の場合、PHPスクリプトファイルとして読み取られて評価されたが、開始タグがない(壊れている)ので、テキストファイルを読み込まれたのと同じ状態。

<?php
    private $size = 4;
fstat.size = 4
========file_get_contents
<?php echo time() . PHP_EOL; ?>
<?php echo time() . PHP_EOL; ?>
<?php echo time() . PHP_EOL; ?>
========require
<?ph

PHPスクリプトとして中途半端な文字数にすると、構文エラーとなる

fstat.size = 25
========file_get_contents
<?php echo time() . PHP_EOL; ?>
<?php echo time() . PHP_EOL; ?>
<?php echo time() . PHP_EOL; ?>
========require

Parse error: syntax error, unexpected end of file, expecting "," or ";" in non-exists-file on line 1

Process exited with code 255.

受信できるサイズより大きい場合はどうなるだろうか?
これは問題ないっぽい。ストリームのブロックサイズやstream_eof()の内容とも関係してくるのかな、というのも気になる。

fstat.size = 320
========file_get_contents
<?php echo time() . PHP_EOL; ?>
<?php echo time() . PHP_EOL; ?>
<?php echo time() . PHP_EOL; ?>
========require
1695458524
1695458524
1695458524

ちょっとだけphp-srcを読んで見る・・・

php_stream_read_to_str とか _php_stream_read の辺りを読んでいけば良いのかなーって思った。

お腹が空いたのでここまで、また気が向いたらやろうかなー。未定。

*1:stream_read()に渡されるデータサイズ。$count。

「PHPのファイルに差分があるかを(astを使って)調べる君」を書いた

つくった

gist.github.com

なんで

ってことで、試し書き程度にやってみたのでした。
(ちゃんと動くのかな・・・?そんなにしっかり確かめてない。なんとなく行けるのかな、って所まで作ったので晒す)
(ちなみに、関数のPHPDocは全部AI Assistantさんがやってくれました)


人に説明や証明する事が面倒くさくてぇ、受け取った側も億劫でぇ・・・みたいなものが世の中にあると、
「説明や証明をしなくて済めばいいのに!あるいは、どっかの誰かが代わりにやってくれれば良いのに!」って思いますよね。
いちいち、そういう”くだらなさ”で仕事の場面やらでストレス溜めたくないなぁ〜って思いつつ、
でも「ガガッと気になったところをぶち潰して行きたい衝動に駆られることはある」のも自分にとっては真なので、
サボるための道具を作って遊んでみるか?というアレです。

モノタロウさんの記事、初めて見た時にメチャクチャ衝撃を受けて。「いいなぁ!あれ、俺も欲しい!!」という感じで。
「コメントとかインデントとか改行とかを変えましたよ!!」みたいな、PHP-CS-Fixerなどでガガーっとやるような変更について、どうでもいいからLGTMくれよーーーって交渉や説得・説明が面倒くさすぎます。

で、「何かASTとかそういうの触れてみたい、遊んでみたい!」とも思っていたので再発明でございます。

どんな感じの

といっても、ツイートで触れている記事で紹介されている actionsを見ながら、写経したようなもんです。 github.com

変えたところとしては

とかとかやりました。
比較したいブランチ名やコミットハッシュを2つ渡してあげる〜みたいな使い方をします。
2つ目は、省略したらHEAD を利用します。

 $ php prototype.php main tmp
# Check diff between main...tmp
| main | tmp |
| ---- | ---- |
| 48261f6f838b529b003fa3a26eb770ea2b7bf06c wip | 6c0c3b15f07051277993e24b7ce876e0a5baa3c4 Create README |
## Diff
### non-PHP Files
| filename | status |
| ---- | ---- |
| README | A |
### PHP Files
| filename | status | BASE | HEAD | ast-changed |
| ---- | ---- | ---- | ---- | ---- |
| hello.php | M | b9b45a8d7d4608bce4541443e0db1ec7 | b9b45a8d7d4608bce4541443e0db1ec7 | NO CHANGE |
| prototype.php | M | 39bfc6a9f6632f1723bc13d5b234c396 | 3278e5a8d39c10c4cb30b3232af507d7 |  |
| src/Command/EchoHashCommand.php | D | f5612c756ba27d3be6a479387ee97dcd |  |  |
| src/Parser/Parser.php | D | db232594d101bc1a7e4f40e67e6dc54c |  |  |
| src/Parser/Validation.php | D | 69850a9556020ed7d4234cc13f1d1c57 |  |  |

(気が向いたら)

  • symfony/consoleとかを使って、なんかそれっぽい感じに書き直したら楽しそう
    • pharで固めるか、Dockerで動くようにするかかなぁ。使いたい環境でサクッと使えるようにしたい
  • GItHub上で使えるようにして、レビュアー大歓喜!号泣!!みたいなものにしたら面白そう
    • PRのコメントに「えいっ!!」って書き込んだら結果を貼り付けてくれる〜、みたいなの出来たら使えそう?

やったこと・書いたもの{2023,06}

OSS

勉強会・LT

PHPカンファレンス福岡2023に参加しました & 登壇しました #phpconfuk / @自分の登壇まわり - 大好き!にちようび

その他

会社でテックブログを(仮)始動させたので、Zennにいくつか記事を出しました。

会社のアカウントからも出しています

PHPカンファレンス福岡2023に参加しました & 登壇しました #phpconfuk / @参加の感想

他の参加者のエントリーを見ていると、どうやらアイキャッチ画像をラーメンにしておくのが流行っているみたいなので、当方もしてみむとてするなり。

6月24日に開催された、HPカンファレンス福岡2023に参加しました

phpcon.fukuoka.jp

ここ最近は、カンファレンスに参加する度(たび)に段々と楽しんだ度(ど)が増してるな〜〜という気持ちがあるのですが、 今回もまた、それはもう楽しかったです。

自分の発表内容については別途で記事を書きまして、イベントやコミュニティに参加して楽しかったな〜という話をしたいと思いますので、ここでは自分の発表内容についての諸々を残しておきたいと思います。

(ほぼ、ただの日記です)

続きを読む

PHPカンファレンス福岡2023に参加しました & 登壇しました #phpconfuk / @自分の登壇まわり

6月24日に開催された、PHPカンファレンス福岡2023に参加しました

phpcon.fukuoka.jp

ここ最近は、カンファレンスに参加する度(たび)に段々と楽しんだ度(ど)が増してるな〜〜という気持ちがあるのですが、 今回もまた、それはもう楽しかったです。

参加した感想やセッションを聴いての感想などは、別途で記事を書きたいと思いますので、ここでは自分の発表内容についての諸々を残しておきたいと思います。

発表したもの

fortee.jp

続きを読む