php – こみなのメモ帳 / 趣味と実益のネタ帳 Sun, 28 Dec 2025 09:52:34 +0000 ja hourly 1 https://wordpress.org/?v=6.1.1 OneThirdCMSを動かしてみたかった話 (2) /archives/1647/ /archives/1647/#respond Thu, 12 Jun 2025 16:06:58 +0000 https://www.komina.info/?p=1647 前回、PHP8.1では動かすことが叶わず、PHP7系が必要だったことが判明したところで終わりました。あのままフェードアウトする予定だったのですが、少しモチベーションが回復してDockerイメージのベースをちょいと変えるだけということに気づいたので、もうちょっとだけ頑張ってみることにしました。

というわけで Dockerfile の一行目を以下のように書き換えてビルドしなおしました。

FROM php:7.4-apache-bullseye

エラーが出ずにインストール完了しました。さっそくURLに /login を付けてログインしてみることにします。

ん?なんだかデザインが崩れているような。開発者ツールでコンソール出力を確認してみたところ、以下のようなエラーが。

Azureで生成される長いURLのせいで難しいことが書いてあるように見えますが、よくよく読むとスタイルシートの読み込みで https を使っていないことで怒られているようです。このせいでスタイルシートが読み込まれなかったようです。

デザイン崩れはしょうがないとして、ユーザIDとパスワードを入力してみたのですが、ログイン失敗になってしまいます。どうやらログインは ajaxで処理されていてそのエンドポイントのURLがこれまた https を使っていないことでエラーになっていました。

これはおそらく Azure App Service 側の問題のような気がしてきました。プログラム側からホストのURLを取得したときに https://… ではなく http://… と認識されてしまっているのかも?

いったんサービスを停止し、/backup/data 配下を確認してみることにします。(うまくスクリプトが動いていればコンテナ停止時にコンテナ内の /var/www/html 配下のファイルが /backup/data へ同期されて見えるようにっているはずです)

そこで config.php というファイルが作成されているのを見つけ開いてみると案の定、http:// で設定されていました。オンラインインストール時にこのURLで登録されたのでしょうか。

	// path
	$config['site_path'] = '/var/www/html';
	$config['site_url'] = "http://onethirdcms-g9gtarhtafc3dte9.japaneast-01.azurewebsites.net/";
	$config['site_ssl'] = "http://onethirdcms-g9gtarhtafc3dte9.japaneast-01.azurewebsites.net/";
	$config['files_path'] = '/var/www/html/files';
	$config['files_url'] = "http://onethirdcms-g9gtarhtafc3dte9.japaneast-01.azurewebsites.net/files/";

config.php の当該箇所を修正して再アップロード。サービスを起動しなおします。

開発ツールを起動しながらページを開くと、今度は Mixed Contentエラーは出なくなりました。スタイルシートのリンクも https://… に切り替わっています。:-)

これでイケるのかも!と思って /login へアクセスしてみたのですが何とエラーも何も出ずホームページのまま。ログイン画面へ遷移しなくなってしまいました。開発者ツールにはエラーは出ない。ログイン画面が表示されない。状況は悪化してしまいました。

これ以上は内部の仕組みを調べながらでないと難しそう。今度こそあきらめることにします。ここまで読んでいただきありがとうございました。ということで OneThirdCMSを動かしたい方は実績のあるレンタルサーバを使いましょう。さよなら。

追記

ローカル環境ではログインしてCMSとして使えそうなので、ローカル環境で作成した資材を Azure App Service の公開フォルダへアップロード(config.phpを除いて)するという手が使えるかもしれません。ちょっと手間ですがローカルPC側の backup.sh で工夫すれば自動で同期をとるといった方法も使えるかもしれませんね。

追記2

少し稼働してみて気づいたこと。コンテナ起動時のスクリプトで停止シグナルはトラップするようにしており、手動でApp Serviceを停止したり再起動するときはトラップできているようですが、アクセスが途絶えて自動でシャットダウンするときには動いていないようです。

どうやら App Service on Linux はそうゆうものらしく、カスタムコンテナ以外ならスタートアップスクリプトに仕込むことで対処できるような話が見つかりました。

今回はカスタムコンテナなので初っ端に docker run が動いてしまうので対処のしようが無さそうです。

Copilotに相談したらに Azure Container Apps を使えば?みたいな回答をいただきました。

]]>
/archives/1647/feed/ 0
OneThirdCMSを動かしてみたかった話 (1) /archives/1610/ /archives/1610/#respond Mon, 09 Jun 2025 08:54:20 +0000 https://www.komina.info/?p=1610 このサイトはWordPressをAzureのAppServiceのフリープラン+CDNで細々と運用していまが、あまりお金をかけてないためWordPressが不安定なところが否めず。何かよい引っ越し先はないかと「軽量で無料なCMSを探しています」的な質問を Copilot に尋ねてみたわけです。

すると福岡発の純国産CMSであるOneThirdCMS(公式ページ https://onethird.net/)を推してくるではありませんか。SQLiteもサポートしていてDBサーバを必須としていないところもポイント高い。というわけで、さっそく試してみることにしました。

結論から言うとうまく行かなかったのですが、紆余曲折あり長くなったので記録もかねてここに記しておきます。

Dockerコンテナで動かす

ダウンロード資材は2種類あって、1つはWindowsPCでWebサーバを起動してその上でOneThirdCMSを動かすもの。もう1つはWebサーバ上で動くオンラインインストーラ。

私のゴールは Azure AppService(F1プラン)で単一コンテナで動かすことなので後者を使うことにします。Docker 公式の phpapacheコンテナを動かせばすぐに使えるかと思ったのですが・・・

  • mod_rewrite が必須(=Apacheで動かすことが前提)。これがクリア。
  • SQLiteで稼働する予定でも pdo_mysql が有効になっている必要あり。
  • オンラインインストールでzip展開するのでzipが有効になっている必要あり。
  • PHP8.2 から導入された仕様「動的プロパティの作成が非推奨」により "Deprecated: Creation of dynamic property Ut::$circle is deprecated in /var/www/html/module/utility.php on line 296 OneThird CMS" というようなエラーが発生するので PHP8.1 で動かす。

ということで php:8.1-apache-bookworm をベースに Dockerfile を作成しました。

FROM php:8.1-apache-bookworm

# Install zip & mysql
# Install required packages
RUN apt-get update && apt-get install -y libzip-dev locales

# Install PHP extensions
RUN docker-php-ext-install zip pdo_mysql

# Set up Japanese locale
RUN sed -i '/^# *ja_JP.UTF-8 UTF-8/s/^# *//g' /etc/locale.gen && \
    locale-gen && \
    update-locale LANG=ja_JP.UTF-8

ENV LC_ALL=ja_JP.UTF-8

# Set timezone to Asia/Tokyo
RUN apt-get install -y tzdata && \
    ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
    echo "Asia/Tokyo" > /etc/timezone

# Set cron 
RUN apt-get install -y cron

# Set rsync
RUN apt-get install -y rsync

# enable rewrite
RUN a2enmod rewrite

# custom php entrypoint
COPY custom-php-entrypoint "/usr/local/bin/"
RUN chmod +x "/usr/local/bin/custom-php-entrypoint"
ENTRYPOINT [ "/usr/local/bin/custom-php-entrypoint" ]
CMD ["apache2-foreground"]

WORKDIR /var/www/html

Docker勉強中なのでイケてないところがあるかもしれません。

githubのプライベートレポジトリにまとめていますが、GitHub Actions の勉強もかねて Docker Hubへ公開しています(https://hub.docker.com/r/komina77/onethirdcms)。使い方らしきものも書きました。

なぜ App Service の PHP8.1 を使わないか

App ServicePHP8.1で動かせばいいじゃないか、と思われるかもしれません。FTPSで公開用ディレクトリにオンラインインストーラ index.php を置くだけ済みそうです。

でもダメでした。

公開用のディレクトリ /homeAzure FilesCIFS/SMB をマウントして永続化していて、そのために POSIX のファイル操作の原子性や即時反映が期待通りに動作しなかったようです。(writableチェックとして、ファイルを複製して、元ファイルを削除、直後に再作成、でエラーになっている。ここまで念入りにチェックしていることにビックリした)

Webサーバも nginx を使っているようなので上記をクリアしてもおそらく mod_rewrite の問題で不可。

というわけで カスタムコンテナで PHP8.1 + Apache を動かす選択をするに至りました。コンテナ内のファイルシステムであればPOSIX準拠の動作になりますのでオンラインインストーラのチェックはクリアするかと。一方でファイルは一時ストレージに保持されることになるため、コンテナ停止時には /home へデータを退避は必要。

Azure App Serviceで動かす

Azure で リソースの作成>Web アプリ でリソースを作成します。公開方法を「コンテナ」、OSはLinux、価格プランを「Free F1(共通インフラストラクチャ)」を選びます。

App Serviceの設定をする

設定>環境変数

変数名設定値説明
WEBSITES_ENABLE_APP_SERVICE_STORAGEtrueApp Service機能。
コンテナ内 /home 配下が永続化されFTPでアクセスできる。
BACKUP_DIR/home/backupkomina77/onethirdcms 向け設定。
永続化対象のディレクトリを意識する。
BACKUP_CRON0 * * * *komina77/onethirdcms 向け設定。
cron書式。永続化のスケジュール。0 * * * * は毎時0分ごと。

設定>構成

  • FTPを使えるようにする。
    • SCM基本認証の発行資格情報をON
    • FTP基本認証の発行資格情報をON
    • FTPの状態をFTPSのみ
  • デプロイ>デプロイセンター>FTPS資格情報 に有効な値が表示されるのでFTPクライアントに登録する。

デプロイ>デプロイセンター>設定

項目設定値
ソースContainer Registry
コンテナの種類単一コンテナー
レジストリ ソースDocker Hub
リポジトリ アクセスパブリック
完全なイメージの名前とタグkomina77/onethirdcms:latest
スタートアップファイルまたはコマンド空欄
継続的デプロイOFF
WebhookURL空欄

準備作業

komina77/onethirdcms ではコンテナ起動時に ${BACKUP_DIR}/backup.sh 、コンテナ停止時に ${BACKUP_DIR}/restore.sh が実行されるようになっています。また、${BACKUP_CRON} が設定されていれば定期的に ${BACKUP_DIR}/restore.sh が実行されます。

komina77/onethirdcms では /var/www/html 配下がサイトとして公開されるようになっているので、${BACKUP_DIR}/data/var/www/html の間でファイルを同期するようなスクリプトを用意しておくことで公開資材を永続化することができるという仕組みです。

そこで、FTPクライアントから以下のスクリプトを保存したファイルを /${BACKUP_DIR} から /home を除いたディレクトリにアップロードしておきます。(${BACKUP_DIR}=/home/backup であれば、/backup/backup.sh, /backup/restore.sh という感じです)

#!/bin/sh

# 環境変数チェック
if [ -z "$BACKUP_DIR" ]; then
    echo "Error: BACKUP_DIR environment variable is not set"
    exit 1
fi

# ソースディレクトリ確認
SRC_DIR="/var/www/html"
if [ ! -d "$SRC_DIR" ]; then
    echo "Error: Source directory $SRC_DIR does not exist"
    exit 1
fi

# バックアップ先ディレクトリ作成
DEST_DIR="$BACKUP_DIR/data"
mkdir -p "$DEST_DIR"
if [ $? -ne 0 ]; then
    echo "Error: Failed to create backup directory $DEST_DIR"
    exit 1
fi

# バックアップ実行
echo "$(date '+%Y-%m-%d %H:%M:%S') - Starting backup: $SRC_DIR → $DEST_DIR"
rsync -a --delete "$SRC_DIR/" "$DEST_DIR/"
if [ $? -eq 0 ]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') - Backup completed successfully"
    exit 0
else
    echo "$(date '+%Y-%m-%d %H:%M:%S') - Error occurred during backup"
    exit 1
fi
#!/bin/sh

# 環境変数チェック
if [ -z "$BACKUP_DIR" ]; then
    echo "Error: BACKUP_DIR environment variable is not set"
    exit 1
fi

# バックアップソースディレクトリ確認
SRC_DIR="$BACKUP_DIR/data"
if [ ! -d "$SRC_DIR" ]; then
    echo "Error: Backup directory $SRC_DIR does not exist"
    exit 1
fi

# 復元先ディレクトリ確認/作成
DEST_DIR="/var/www/html"
mkdir -p "$DEST_DIR"
if [ $? -ne 0 ]; then
    echo "Error: Failed to create restore destination directory $DEST_DIR"
    exit 1
fi

# 復元実行
echo "$(date '+%Y-%m-%d %H:%M:%S') - Starting restore: $SRC_DIR → $DEST_DIR"
rsync -a --delete "$SRC_DIR/" "$DEST_DIR/"
if [ $? -eq 0 ]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') - Restore completed successfully"
    exit 0
else
    echo "$(date '+%Y-%m-%d %H:%M:%S') - Error occurred during restore"
    exit 1
fi

OneThirdCMSのインストール作業

OneThirdCMSを動かす環境が準備できたらインストール作業を行います。

  • OneThirdのダウンロードからオンラインインストーラをダウンロードし解凍する。
  • FTPクライアントから解凍したファイル index.php/${BACKUP_DIR}/data から /home を除いたディレクトリにアップロードする。
  • App Service の 概要 へ
    • 開始されてなかったら開始をクリック。
    • 参照をクリックすると公開されているURLが別タブで開く。このURLへのアクセスがトリガになってコンテナ起動となる。初回はコンテナのプルから始まるので時間かかります。
うまく準備ができていればブラウザに図のような画面が表示される

[Start Download OneThird CMS] ボタンをクリックするとダウンロードが走ります。

ダウンロードが終了するとインストールボタンが表示される

[Install OneThird CMS] ボタンをクリックすると資材が解凍されてインストールが開始されます。1項目ずつチェックが入り、見た目もかっこいいです。

今回はSQLiteを使うので [インストール(SQLite)] をクリック。

Admin ID や Admin password を適当に入れて、jQuery はCDN参照を選んでインストール開始します。

順調にインストールは進み・・・

成功したように思いきやなんかエラーが出てしまった。

うむ。私はPHP5までの人なのだが、どうやら PHP8 で非推奨になった書き方についてのエラーのようだ。PHP8.1からさらにPHP7系に戻すのもセキュリティ的に問題ありですし(PHP8.1もセキュリティサポート切れてますが)、ソースを直してまで稼働するところまで持っていく義理もなく。。

残念だがここで中断することにした。おそらくこういった非推奨エラーになるところを一つ一つ潰していけば、この興味深いCMSは動くようになると思われる。

(よくよく見るとローカルPCで動かす版のPHPもバージョン7のようだ :-))

中途半端になってしまったが、無駄にAzure App Serviceの知識が増えたところで今回はあきらめることにした。長々と読んでいただいた方、結果がパッとせず申し訳ない。

]]>
/archives/1610/feed/ 0
[php]PHPのチートシート(Web編) /archives/511/ /archives/511/#respond Wed, 28 Oct 2020 21:00:00 +0000 https://www.komina.info/?p=511
【注意】
この記事は過去に別サイトで執筆したものを再掲載したものです。
内容が古くなっていて現在では適用できない場合や、もっと良い方法が出来ている場合があります。
 

設定

アップロードするファイルサイズを大きくする

php.ini設定を下記のように変更する。

post_max_size = 16M
upload_max_filesize = 16M
file_uploads = On

POSTサイズの制限も影響を受けるので、php.iniとともに変更する。

バージョン表示を消す

PHPが出力するヘッダにはPHPのバージョン情報も含まれる。
PHPのバージョンを表示することはセキュリティ面から好ましいとは言えないので、特に理由がない限りはOFFにしておくのが好ましい。

expose_php = OFF

リクエストの取得

GETメソッドおよびPOSTメソッドによってブラウザより渡されるデータの取得方法について。

GETメソッド

システム変数、$_GET[ ]を参照する。

<input type="text" name="abc">

このようなフォームからリクエストを受け取る場合は次のように記述する。

$var = $_GET["abc"];

取得できない場合は、nullが返される。

POSTメソッド

システム変数、$_POST[ ]を参照する。

<input type="text" name="abc">

このようなフォームからリクエストを受け取る場合は次のように記述する。

$var = $_POST["abc"];

取得できない場合は、nullが返される。

GET、POST共通

システム変数、$_REQUEST[ ]を参照する。
$_REQUEST[ ]では、GETメソッド、POSTメソッド両方からのデータ取得が出来る。

本来POSTされるべきデータをGETで偽装された場合に区別できないので推奨されない。

チェックボックスの処理

チェックボックスでの複数チェックの状態を取得するには、HTMLは次のように記述する。

<input type="checkbox" name="abc[]" value="01">選択肢A
<input type="checkbox" name="abc[]" value="02">選択肢B
<input type="checkbox" name="abc[]" value="03">選択肢C

name属性を「abc[]」として配列表記にしておく。
PHP側でデータを参照すると配列変数として得られる。

次のように添え字ありでも構わない。

<input type="checkbox" name="abc[1]" value="01">
<input type="checkbox" name="abc[k001]" value="01">

このチェック状態を”hidden”にて次のフォームへ渡す場合も、同様に記述する。

<input type="hidden" name="abc[]" value="01">
<input type="hidden" name="abc[]" value="02">

ファイルの受信

フォームの記述は、で enctype=”multipart/form-data” を指定する。
ファイル選択は、<input type=”file”> にて配置する。

<!-- サンプル -->
<form enctype="multipart/form-data" method="post" action="getimage.php" >
 <input type="file" name="fileA">
 <input type="file" name="fileB">
 <input type="file" name="fileC">
 <input type="submit" value="送信">
</form>

PHP側では受け取ったファイルをテンポラリに保存する。
テンポラリを作るディレクトリは、php.iniで設定する。

; 設定例
upload_tmp_dir = "C:\xampplite\tmp"

スクリプトでは、$_FILES配列変数を参照することで、ファイルの詳細を得ることが出来る。
ファイルを1つ選び、残り2つは空欄で送信した場合の$_FILESは以下の通り。

fileA
namereadme.txt
typetext/plain
tmp_nameC:\xampplite\tmp\php31.tmp
error0
size2435
fileB
name
type
error4
size0
fileC
name
type
error4
size0
$_FILES[ ]

元ファイル名、サイズ、テンポラリファイルのパスが入っているので、これを利用する。
保存されたファイルはスクリプトの終了時に削除されるので、必要ならコピーしておく必要がある。

セッション

セッションを使用するとスーパーグローバル配列変数$_SESSIONを使用して、セッション機能を利用できる。

セッションの開始/破棄

明示的に開始する場合は、session_start()関数を使用する。
既にセッションが開始されている場合は保存されているセッションデータが読み込まれる。

session_start();

php.iniの設定で自動開始とすることもできる。

[Session]
session.auto_start = 1

明示的にセッションを破棄する場合は、session_destroy()関数を使用する。

session_destroy();

明示的に破棄しないとサーバに情報が残り続けるので、自動破棄する機構がある。
セッションの有効時間を何秒とするか、php.iniの設定

session.gc_maxlifetime = 1440;  // = 24min  (24 x 60sec)

期限切れセッションデータの物理削除処理(ガベージコレクション)の起動設定。
session_start()関数が呼ばれるたびに、以下の設定値を用いて確率試行が行われる。

// 1/100の確率でGC起動
session.gc_probability = 1
session.gc_divisor = 100

セッションデータの利用

スーパーグローバル配列変数$_SESSIONを使用する。配列と同じ扱いで良い。

$_SESSION['name'] = $name;   // セッションへ登録
if (isset($_SESSION['name'])) {
   print $_SESSION['name'].'さん、こんにちは!';     // 登録内容の利用
}

特定の要素を削除する場合は、unset()関数にて要素を削除できる。

unset($_SESSION['name']);

全ての要素を削除する場合は、新たに配列を割り当てる方が早い。

$_SESSION = array();

Smarty

有名なテンプレートエンジン。テンプレートは標準でファイルを使用する。ファイル以外のリソースを使用する場合は、register_resource()メソッドにて自前で用意した関数を登録する必要がある。

ファイル以外のリソースを使う

http://ml.php.gr.jp/pipermail/php-users/2004-March/021324.html
テンプレートをメモリーから読み込むサンプルが書かれているが、このままではNG。
$smarty->fetch("hensu:".$tmpl); としているが、$tmplの中身がそのままコンパイル結果の保存ファイル名になってしまう。
したがって保存ファイル名が、ファイル名として適切で無い状態になってしまうと落ちることがある。
参考: https://www.smarty.net/docsv2/ja/template.resources

“{” や “}” を本文で使う

Smrty処理しない範囲が決まっているなら、{literal}{/literal}タグで囲む。
スポット的ならそれぞれ、{ldelim}および{rdelim}が対応している。

]]>
/archives/511/feed/ 0
[php]PHPのチートシート /archives/509/ /archives/509/#respond Tue, 27 Oct 2020 21:00:00 +0000 https://www.komina.info/?p=509
【注意】
この記事は過去に別サイトで執筆したものを再掲載したものです。
内容が古くなっていて現在では適用できない場合や、もっと良い方法が出来ている場合があります。
 

入手

すぐに始めるにはXAMPP環境が便利。

比較演算子

  • 型変換が自動で行われる以外は、C言語などの比較演算子と同じ。
  • 厳密チェックのために”===”,”!==”という演算子が用意されている。
    • ’10’が数値なのか、’1’と’0’から成る文字列なのか、区別される。
    • nullと ” も厳密比較しないと同じとして扱われる。
演算子意味
===オブジェクトの型も含めて一致している
!==オブジェクトの型も含めて一致していない

変数

通常、厳密な型チェックは行われない。

変数が数値型かどうか

変数の値がinteger型かどうか確認するには、is_int()関数を用いる。

$val1 = 10;
$val2 = '20';
if (is_int($val1)) { .... }
if (is_int($val2)) { .... }

文字列

文字列から数値を取得

  • intval()、floatval()、doubleval()関数を使う。
  • intval()関数では、第二引数で基数を指定できる。
$imm = intval($str);

16進文字列を数値に変換

  • intval()関数の基数を指定する。
$imm = intval('1234', 16);

文字列をセパレータで分解する

  • split( ), spliti( ), explode( )関数を使う。
  • split( ), spliti( )は、セパレータ文字の指定で正規表現が使える。
  • spliti( )はアルファベットの大文字と小文字を区別しない。
  • explode( )は正規表現が使えない代わりに高速。

配列

動的配列、連想配列、の機能を持つ。

配列の定義方法

$sample = array('a', 'b', 'c');

配列にキーが存在するか

  • array_key_exists()関数を用いる。
  • 存在しないキーを用いて値を取得しようとしてもエラーにはならない。nullとなる。
if (array_key_exists('name', $sample)) {
    // 存在する
}

ある変数が配列かどうか

  • ある変数が配列かどうかを確認するには、is_array()関数を用いる。
  • 配列ならtrueを返す。
$result = is_array($table);

配列からの特定の要素を削除する

unset( )関数を用いる。

$sample = array('while'=>7, 'bule'=>2, 'red'=>1);
unset($sample['white']);

配列の要素数を調べる

count( )関数、もしくはsizeof( )関数を用いる。

$i = count($sample);
count()関数について
  • 配列もしくはCountableインタフェースを実装したオブジェクトの要素数を返します。
  • 普通の変数であれば1。nullであれば0を返します。
  • 第二引数でモードを指定することもできる。
    • 省略するとCOUNT_NORMAL。指定変数の要素数のみ返す。
    • COUNT_RECURSIVEを指定すると再帰的にカウントする。

計算

四捨五入、切り捨て、切り上げ

  • それぞれ、round( )、floor( )、ceil( )関数で行う。
  • 小数点以下の処理となる。(round( )のみ桁指定可能)
  • 例えば、100の倍数になるようにするならば下記のようにして対応する。
$result = floor($value / 100) * 100;
$result = ceil($value / 100) * 100;
$result = round($value, -2);
]]>
/archives/509/feed/ 0