PHP 初心者が WordPress の プラグイン 作成 ! part17 ( PHPからヘッドレスブラウザ操作 また失敗 )

この記事では PHP 初心者 が WordPress プラグイン を 作成 します。 part17 では再度PHPからヘッドレスブラウザを操作してみようと思います。

前回、PHPからヘッドレスブラウザを操作すべく四苦八苦しながら作業を進めました。
しかし残念ながらヘッドレスブラウザが起動せずいったん中断。

PHP 初心者が WordPress の プラグイン 作成 ! part16 ( PHPからヘッドレスブラウザ操作 失敗 )

今回は中断したところから再びスタートします。

調査

調査したところ、環境の問題のようでした。
今回プラグイン開発の環境としてDockerコンテナを使用しています。
ヘッドレスブラウザもDockerコンテナにインストールしました。

どうやらDockerからヘッドレスブラウザを動かす権利がない(?)ようです。
回避方法としてコンテナ起動時に特権モードを使用する方法やヘッドレスブラウザのオプション(–no-sandbox)を使用する方法があるようです。

特権モードはなんか怖いなぁ・・・というところがあるので–no-sandboxを付与してみようと思います。
ところでPHPではどのように指定するのか・・・。とこちらも調査してみたところありました!

Docker でヘッドレス Chrome を動かしてみた

しかもドンピシャ(死後)な実装です😍

<?php
require_once('./vendor/autoload.php’);
use HeadlessChromium\BrowserFactory;

$browserFactory = new BrowserFactory('/usr/bin/chromium-browser’);

$options = [
'headless’ => true,
'noSandbox’ => true ,
];
$browser = $browserFactory->createBrowser($options);

$page = $browser->createPage();
$page->navigate('https://www.yahoo.co.jp/’)->waitForNavigation();

$pageTitle = $page->evaluate('document.title’)->getReturnValue();
echo $pageTitle, PHP_EOL;

$browser->close();

 

実装

なるほど🤔連想配列(Map? Dictionary?)を作成しそこにnoSandboxの指定を記述するんですね。
headlessの記述も必要なのでしょうか?わからないので私もこのように指定しておきます。

$options = [
    'headless' => true,
    'noSandbox' => true ,
];
$browser = $browserFactory->createBrowser($options);

確認

それでは確認してみます。
http://localhost:8099/index.phpにアクセスします。

今度はうまくいきますように・・・

ガーン😫

Fatal error: Uncaught TypeError: implode(): Argument 
#2 ($array) must be of type ?array, string given in /var/www/html/vendor/wrench/wrench/lib/Wrench/Protocol/Protocol.php:316 Stack trace: 
#0 /var/www/html/vendor/wrench/wrench/lib/Wrench/Protocol/Protocol.php(316): implode(Array, '\r\n') 
#1 /var/www/html/vendor/wrench/wrench/lib/Wrench/Client.php(233): Wrench\Protocol\Protocol->getRequestHandshake('ws://127.0.0.1:...', 'VqOQRduiyyM8su9...', 'http://127.0.0....', Array) 
#2 /var/www/html/vendor/chrome-php/chrome/src/Communication/Socket/Wrench.php(97): Wrench\Client->connect() 
#3 /var/www/html/vendor/chrome-php/chrome/src/Communication/Connection.php(156): HeadlessChromium\Communication\Socket\Wrench->connect() 
#4 /var/www/html/vendor/chrome-php/chrome/src/Browser/BrowserProcess.php(144): HeadlessChromium\Communication\Connection->connect() 
#5 /var/www/html/vendor/chrome-php/chrome/src/BrowserFactory.php(73): HeadlessChromium\Browser\BrowserProcess->start('/usr/bin/chromi...', Array) 
#6 /var/www/html/index.php(24): HeadlessChromium\BrowserFactory->createBrowser(Array) 
#7 {main} thrown in /var/www/html/vendor/wrench/wrench/lib/Wrench/Protocol/Protocol.php on line 316

またしても失敗です。今度はヘッドレスブラウザのライブラリが依存するライブラリ内でエラーが起きているようです。

PHP Fatal error: Uncaught TypeError: implode(): Argument #2 ($array) must be of type ?array, string given in

英語はよくわかりませんがまだ未修正という風に見えます。

この部分だけ自分で修正できないかな?と思いこちらも調査しました。

PHP Fatal error: Uncaught TypeError: implode(): Argument #2 ($array) must be of type ?array, string given in

implodeの2番目のパラメータが配列でないといけないということらしいです。

該当箇所をのぞいてみます。
/var/www/html/vendor/wrench/wrench/lib/Wrench/Protocol/Protocol.php(316)

2番目のパラメータは「文字列」になっていますね。

公式サイトでもPHP8ではこの記述はできないとされています。
つまりライブラリがPHP8に対応していないということですね。
なぜPHP8にしてしまったのか・・・

implode

2番目のパラメータは「セパレータ」を表現しているのですね。
PHP8からは「セパレータ」は1番目のパラメータに定義することになったようです。

Wrenchライブラリを修正してみる

とりあえずこう・・・直してみます。

同、ファイル内に同じ問題があったのでこちらも修正(類似問題)。

ほかにもたくさんありそうですがまずはこれだけにしておきます😦

再確認

今度はどうでしょうか。

😩

Fatal error: Uncaught HeadlessChromium\Exception\OperationTimedOut: Operation timed out (5sec) in /var/www/html/vendor/chrome-php/chrome/src/Utils.php:69 Stack trace: 
#0 /var/www/html/vendor/chrome-php/chrome/src/Communication/ResponseReader.php(108): HeadlessChromium\Utils::tryWithTimeout(5000000, Object(Generator)) 
#1 /var/www/html/vendor/chrome-php/chrome/src/Communication/Session.php(84): HeadlessChromium\Communication\ResponseReader->waitForResponse(5000) 
#2 /var/www/html/vendor/chrome-php/chrome/src/Browser.php(170): HeadlessChromium\Communication\Session->sendMessageSync(Object(HeadlessChromium\Communication\Message)) 
#3 /var/www/html/index.php(27): HeadlessChromium\Browser->createPage() 
#4 {main} thrown in /var/www/html/vendor/chrome-php/chrome/src/Utils.php on line 69

まとめ

PHPからヘッドレスブラウザ操作に再挑戦しました。
またしても失敗でしたが着実に進んでいるように感じます。
次はうまくいきそうな予感です(笑

index.phpの全体像は以下のようになりました。

<?php
// $a = 1;
// if ($a === 1) {
//     echo "ほげ";
// } else {
//     echo "fuga";
// }

// autoloadを読み込む
require 'vendor/autoload.php';

use HeadlessChromium\BrowserFactory;

// whereis chromiumでパスを探した
$browserFactory = new BrowserFactory('/usr/bin/chromium');

// for Docker option
$options = [
    'headless' => true,
    'noSandbox' => true ,
];

// starts headless chrome
$browser = $browserFactory->createBrowser($options);

// creates a new page and navigate to an url
$page = $browser->createPage();
$page->navigate('https://www.google.co.jp')->waitForNavigation();

// get page title
$pageTitle = $page->evaluate('document.title')->getReturnValue();

// screenshot
$page->screenshot()->saveToFile('/var/www/html/bar.png');

// pdf
$page->pdf(['printBackground'=>false])->saveToFile('/var/www/html/bar.pdf');

// bye
$browser->close();

?>

今日はここまで!