osCommerce修正メモ(PHP4.2を5.6にアップデート)

osCommerceのバージョンはosCommerce2.2MS1J-alter(だったと思う)。修正作業は、公開されていた register_globals_offの環境用の修正スクリプト等(osCommerce2.2MS1J-R3用)を適用し、その後発生 するエラーを1つずつ潰していくという泥臭い方法をとった。そのため、デバッグできていない箇所が残っている可能性がある。

■修正作業 その1
register_globals ON を前提に動作するosCommerceを register_globals OFF で動作するよう修正

ここで公開されていたregister_globals OFF用の 修正スクリプト等(手作業による修正を含む)を利用又は参考にして最初の修正作業を行った。
公開されていたスクリプト等は対象がosCommerce2.2MS1J-R3用なので、修正対象のosCommerceより幾分 新しいバージョン用だったが、大きな差はないと考えて修正スクリプトを適用し、紹介されていた手作業での修正を行った。
なお、修正スクリプトが対象としている-R3とはフォルダー構成が異なっていたので修正スクリプトや手作業での修正箇所中の フォルダー名は環境にあわせて修正して適用した。
また、osCommerceの細部のバージョンが異なるため、存在しないスクリプトや修正済みの箇所があったが(alter版だったから?)、 おおむね紹介されていた修正箇所は見つけられた。不要なglobal宣言を潰して行く作業などは比較的時間がかかった。

■修正作業 その2
修正作業 その1の作業中に、PHP.iniのregister_globalsディレクティブをチェックしている箇所もコメントアウトした。
→admin/includes/application_top.php
→includes/application_top.php

■修正作業 その3
修正作業その1の自動置き換えに伴う修正
includes/functions/general.phpで定義しているtep_has_product_attributes()関数で引数に $_SESSION['language_id']を直接使っている箇所があったので他の引数名に置き換えた。 修正作業その1の自動置き換えの影響と思われる。

■修正作業 その4
クラス定義外の$thisを他の変数(例えば$thisisとか)に置き換え
※修正の概要
(1)$thisを$thisisに置き換え
(2)$this->hoge = new Smarty();を$thisis = new stdClass; $thisis->hoge = new Smarty();に置き換え
※(2)のパターンはPHP5以降で標準クラスの生成を省略した場合に警告が出るようになったので、明示的に標準クラスの オブジェクトを生成するようにした。ただし、次の5つのスクリプトは(2)のパターンであっても、呼び出し元ですでに 標準クラスオブジェクトが生成されているため、標準クラスのオブジェクトを生成しないようにした。
includes/column_left.php
includes/column_right.php
includes/modules/also_purchased_products.php
includes/header.php →このスクリプトでは標準オブジェクトが生成されていない場合のみ標準クラスオブジェクトを生成するようにした。
includes/footer.php

■修正作業 その5
PHP5.3で非推奨になったsplit()関数をpreg_split()に置き換え
※preg_split()のパータンは'/'等のデリミタで挟む必要がある。

■修正作業 その6
引数なしのmktime()関数をtime()関数に置き換え
引数なしでmktime()関数を使うと通知が出る(PHP5.1以降)ようになったのでtime()関数に置き換える。

■修正作業 その7
STORE_DB_TRANSACTIONS定数の値が定義される前に参照されている箇所を修正
定数定義の有無を確認して参照するように修正。
admin/includes/functions/database.php
includes/functions/database.php

■修正作業 その8
$PHP_SELFを$_SERVER['PHP_SELF']に置き換え、又は、$PHP_SELFの定義追加
$PHP_SELFはregister_globalsがONの時に使えるグローバル変数。register_globals_OFFでは$_SERVER['PHP_SELF']を使うことになる。 ただし、includes/application_top.php内で$PHP_SELF = $_SERVER['PHP_SELF']を定義しているので、置き換え不要のスクリプトもある。
なお、admin/includes/application_top.phpでは元は$PHP_SELFの定義はないが、逆に$PHP_SELFを追加した方が修正が簡単になる。

■修正作業 その9
重複した定数定義の修正
admin/includes/languages/japanese.php
次の定数が重複定義されていたので、重複部分をコメントアウトした。
IMAGE_ADD_POINTS
IMAGE_DELETE_POINTS
※alter版だけの定数なのかもしれない。

■修正作業 その10
register_globals_OFF関連の修正
$erfが未定義との通知が出る。'?erf'パラメター付きで呼び出される場合があるが、register_globals_OFFの環境では自動で$erfは生成されないので $_GET['erf']が有効な場合は$erfを定義するように修正。
admin/users_login.php

■修正作業 その11
次の関数内で定数SIDが未定義である旨の通知が出るので修正
admin/includes/functions/html_output.phpのtep_href_link()関数
※通知が出ないようにSIDが定義されている場合に参照するように修正したが、SIDが未定義のまま参照される原因まで追求していない。

■修正作業 その12
register globals OFF関連の修正
次の関数内で$GLOBALS[$name]として、'loginuid','loginpwd','exwcute_login'などの未定義のグローバル変数が参照されているとの通知が出るので、 $_POST[$name]又は$_GET[$name]で置き換える。
admin/includes/functions/html_output.php のtep_draw_input_field()関数
なお、includes/finctions/html_output.phpのtep_draw_input_field()関数では、$GLOBALS[$name]の存在を確認してから参照しているので、 $_POST[$name]又は$_GET[$name]で置き換えずに同じような対応でもよいと思われる。

■修正作業 その13
PHPの古いバージョンのスクリプトを置き換え(修正不要かも)
admin/includes/classes/user_certify.php
1 user_certifyクラスのuser_certify()関数内の$GLOBALS['HTTP_POST_VARS']を$_POSTに置き換え。
2 user_certifyクラスのpassword_check()関数内の$GLOBALS['HTTP_POST_VARS']を$_POSTに置き換え。
3 末尾のメイン部分の$GLOBALS['HTTP_GET_VARS']を$_GETに置き換え。

■修正作業 その14
php5.4以降のhtmlspecialchars()関数の仕様変更による修正
php5.4以降はhtmlspecialchars()に渡される文字コードのデフォルトがutf-8になった。そのためEUC-JPなどを使っている場合は 正常に動作しないので、引数に文字コードを指定するようにした。
修正前:htmlspecialchars($string))
修正後:htmlspecialchars($string ,ENT_COMPAT | ENT_HTML401 ,'EUCJP')

■修正作業 その15
register_globals_OFF関連の修正
$GLOBALS['PHP_SELF']を$_SERVER['PHP_SELF']に置き換え
PHP5.4以降では$PHP_SELFはグローバル変数ではないので、$GLOBALS['PHP_SELF']も存在しない。
admin/users.php
admin/users_log.php

■修正作業 その16
PHP5.3で非推奨となったereg(),eregi(),ereg_replace()をpreg_match(),preg_match(i),perg_replace()に置き換え
※preg系はパターン文字列をデリミタ(/等)で囲む必要がある。逆にereg系はデリミタで囲んではいけなかった。 なお、デリミタは基本は'/'を使ったが、パータン文字列に'/'が含まれる場合が1箇所あったのででそこだけ'#'を使った。

■修正作業 その17
includes/modules/order_total/ot_redemptions.phpの111行付近の修正
$gv_ins = tep_db_query("insert into customer_points_redeemed values (null, '" . $_SESSION['customer_id'] . "' , $points_spent, now(), '$insert_id' )");
修正内容は $_SESSION['customer_id']を''で囲っただけ。どうしてエラーになるのか分からないが、これもPHP4とPHP5との仕様差なのか。

■修正作業 その18
includes/functions/sessions.phpの142行付近の修正
ini_set('session.use_trans_sid', $saved_value)でini設定を変更できないとの通知が出る。
ディレクティブの値を保存しておいて、値を0にしてセッションを再作成してから、元の値に復帰しようというものだが、 復帰しないでも大きな影響はない(既定値が0で実行後は元の値に戻るから)のでコメントアウトすることにした。

■修正作業 その19
次の関数の中で警告が出るので修正
includes/functions/general.php で定義しているtep_get_all_get_params()関数の中でstrlen($value)の$valueが文字列ではないという警告が出る。
whileループの手前で$_GETの内容を調べて、配列を含む$_GETは排除することにした。(念のため排除するのは配列に限定した。)

■修正作業 その20
admin/whos_online.php 146行付近のsession_decode()に失敗して通知が出る場合があるので修正
customer関連のデータをデコードしようとするが保持されていないためエラーになるようだ。customer関連のデータが保持されて いないのが正しい動作なのかどうかが分からないが、エラーが出ないように、当面デコードすべきデータの文字列検索でFalseに なっている場合はsession_decodeに渡さないように修正する。

■修正作業 その21
(1)mysql_xxxxx()関数をmysqli_xxxx()関数で置き換える
php5.6からmysql_xxxx関数は非推奨となり通知が出るようになるのでmysqli_xxxx()関数に置き換える。
mysql_系とmysqli_系では引数が異なる場合もあるので関数毎に引数を確認して置き換える。
(2)mysqli_系の関数への置き換えに伴う修正
元のmysql_系では接続IDは省略可能で、実際、OSCでは省略していたが、mysqli_系の関数では(接続IDが引数である場合)接続IDは省略できない。 そのため、接続IDを意図的に保存し、省略されて渡されない引数の接続IDを保存した先から読み込む必要がある。
→includes/application_top.phpの中でデータベースに接続しセッションを開始しているので、tep_session_start()でセッションを開始した直後に そのリンクオブジェクトを$_SESSION['db_link']に保存することにした。
→include/functions/database.phpのtep_db_query()関数で接続ID(リンクオブジェクト)がNULLの時には$_SESSION['db_link']から読み込むように修正した。
→include/functions/database.php内の次の関数も他のスクリプトからコールされるので同様の修正をした。
tep_db_insert_t()関数
tep_db_insert_id()関数
→次の2つのスクリプトについても同様の修正をした
admin/includes/application_top.php
admin/includes/functions/database.php(※tep_db_insert_t()関数はない)

■修正作業 その22
Mysql:クライアントからサーバーへのステートメント送信時の文字セットを指定(EUC-JP)
※Mysqlを4から5.5にアップデートした際に発生した文字化けへの対策として設定したものだが、 環境によっては文字セットの指定が不要な場合もある。(PHPアップデートの事前作業で行った。)
admin/includes/functions/database.phpのtep_db_connect()関数内で(includes/fuinctions/database.phpでも同じ) mysqli_select_db()の直後に文字セットを指定
mysqli_select_db($$link, $database);
mysqli_query($$link, 'SET NAMES ujis'); //<--euc-jp

■修正作業 その23
PHP.iniの修正
PHP5.4以降でカタログ管理で入力した商品説明等の文字が確認ページで文字化けするようになった。
php.iniの設定変更で解決した。設定変更は次のとおり。(コメントアウト行は元の設定)
;mbstring.encoding_translation = On
mbstring.encoding_translation = off
;mbstring.http_input = auto
;mbstring.http_output = EUC-JP
mbstring.http_input = pass
mbstring.http_output = pass


■■■
以上の修正でPHP5.6で動作するようになった。ここに記載したのは修正の要点だけで、実際には手作業で修正するファイルや箇所は結構多い。 修正の対象がosCommerce2.2 MS1J-alterというかなり古いものだったせいか、修正作業 その1でのスクリプトによる自動修正を含めると 修正対象のファイルは約300あった。
デバッグしながら潰していく方法だったので、一応動作するだけで、もしかするとまだ修正が必要な箇所が残っているかもしれない。
■■■

■修正作業 その24
(2019.10.3追加)管理者モードで個別の注文データを修正する際、修正入力後、更新ボタンを押すと個別注文データの中の顧客情報や 請求先情報がクリアされてしまうことがわかった。
問題のスクリプトは/admin/edit_orders.php
原因はphp4をphp5にアップデートしたときに一番問題になるregister_globals ディレクティブ関連。フォームの入力フィールド名と 同じ変数名がそのまま使われていたので、$_POST['フィールド名']で置き換えた。
register_globals関連の修正は一番最初に修正したはずなのにまだ修正が必要なスクリプトが残っていることに少々驚いた。 register_globals関連で修正が必要なスクリプトはまだ残っている可能性が大きい。

ご指摘・ご意見の連絡先:renraku@oscommerce.inblank.net