カテゴリー別アーカイブ: EC-CUBE

EC-CUBE2.11 入力フォームの内容チェック項目メモ

ユーザー入力のフォーム関連のクラスによく

$objFormParam->addParam(“お電話番号1”, ‘tel01’, TEL_ITEM_LEN, ‘n’, array(“EXIST_CHECK”, “SPTAB_CHECK”, “NUM_CHECK”, “MAX_LENGTH_CHECK”));

などと書かれているが、この”EXIST_CHECK”とか”SPTAB_CHECK”とか、実際何をチェックしているのかあいまいだったので調べてみました。

実際のチェックは
/data/class/SC_CheckError.php
に書かれています。

“HTML_TAG_CHECK”: HTMLのタグをチェックする

“EXIST_CHECK”: 必須入力の判定

“EXIST_CHECK_REVERSE”: 必須入力の判定(逆順)

“SPTAB_CHECK”: スペース、タブの判定(スペース、タブ、改行のみの入力はできません。)

“NO_SPTAB”: スペース、タブの判定(スペース、タブ、改行は含めないで下さい。)

“ZERO_START”: ゼロで開始されている数値の判定(0で始まる数値が入力されています。)

“SELECT_CHECK”: 必須選択の判定(選択されていません。)

“EQUAL_CHECK”: 同一性の判定(~と~が一致しません。)

“DIFFERENT_CHECK”: 値が異なることの判定(~と~は、同じ値を使用できません。)

“GREATER_CHECK”: 値の大きさを比較する (~は~より大きい値を入力できません。)

“MAX_LENGTH_CHECK”: 最大文字数制限の判定(○字以下で入力してください。)

“MIN_LENGTH_CHECK”: 最小文字数制限の判定(○字以上で入力してください。)

“MAX_CHECK”: 最大数値制限の判定 (n以下で入力してください。)←コメントでは「最大文字数制限の判定」と書かれているがたぶん間違い。

“MIN_CHECK”: 最小数値制限の判定(n以上で入力してください。)

“NUM_CHECK”: 数字の判定(は数字で入力してください。)

“NUM_POINT_CHECK”: 小数点を含む数字の判定(は数字で入力してください。)

“ALPHA_CHECK”: 半角の判定(は半角英字で入力してください。)

“TEL_CHECK”: 電話番号の判定(数字チェックと文字数チェック)

“FULL_EXIST_CHECK”: 関連項目が完全に満たされているか判定( が入力されていません。)←全部入力されているかのチェック?使われていない?

“ALL_EXIST_CHECK”: 関連項目がすべて満たされているか判定(はすべての項目を入力して下さい。)←たとえば郵便番号など二つのテキストフィールドが入力されているかどうか

“ONE_EXIST_CHECK”: 関連項目がどれか一つ満たされているか判定(どちらか一方が入力されていればOK)

“TOP_EXIST_CHECK”: 上位の項目が満たされているか判定(は先頭の項目から順番に入力して下さい。)←規格の選択などで使用している。

“KANA_CHECK”: カタカナの判定

“KANABLANK_CHECK”: カタカナの判定2(タブ、スペースは許可する)

“ALNUM_CHECK”: 英数字の判定

“GRAPH_CHECK”: 英数記号の判定

“ZERO_CHECK”: 必須選択の判定(ひとつは選択してね)

“NUM_RANGE_CHECK”: 桁数の判定 (○○はn桁~n桁で入力して下さい。)

“NUM_COUNT_CHECK”: 桁数の判定(○○はn桁で入力して下さい。)

“EMAIL_CHECK”: メールアドレス形式の判定

“EMAIL_CHAR_CHECK”: メールアドレスに使用できる文字の判定

“URL_CHECK”: URL”: URL形式の判定

“IP_CHECK”:  IPアドレスの判定

“FILE_EXT_CHECK”: 拡張子の判定

“FIND_FILE”: ファイルが存在するかチェックする

“FILE_EXIST_CHECK”: ファイルが上げられたか確認

“FILE_SIZE_CHECK”: ファイルサイズの判定(制限)

“FILE_NAME_CHECK”: ファイル名の判定(ファイル名に日本語やスペースは使用しないで下さい)

“FILE_NAME_CHECK_BY_NOUPLOAD”: ファイル名の判定(アップロード以外の時)

“CHECK_DATE”: 日付チェック[項目名,YYYY,MM,DD]

“CHECK_DATE2”: 日付チェック[項目名,YYYY,MM,DD,mm]

“CHECK_DATE3”: 日付チェック[項目名,YYYY,MM]

“CHECK_BIRTHDAY”: 誕生日チェック[項目名,YYYY,MM,DD]年の最大・最小数値のチェックがついている

“CHECK_SET_TERM”: 年月日に別れた2つの期間(YYYYMMDD)の妥当性をチェックし、整合性と期間を返す←要するに期間が正しいかどうか

“CHECK_SET_TERM2”: “CHECK_SET_TERM”のもっと細かい期間(YYYYMMDDHHmmss)のバージョン

“CHECK_SET_TERM3”: “CHECK_SET_TERM”の期間が年と月(YYYYMM)だけのバージョン

“DIR_CHECK”: ディレクトリがあるかどうか

“DOMAIN_CHECK”: ドメインの形式チェック

“MOBILE_EMAIL_CHECK”:  携帯メールアドレスのチェック

“CHECK_REGIST_CUSTOMER_EMAIL”: メールアドレスが会員登録されているか調べる

“PROHIBITED_STR_CHECK”: 禁止文字列のチェック

“EVAL_CHECK”: PHPコードとして評価可能かチェックする

FILE_EXIST_CHECK

ECCUBE 2.11 支払い方法に説明文を追加

代引きの手数料など一つ一つの支払い方法に説明文を入れたかったのでカスタマイズのメモ

データベーステーブルdtb_paymentにはmemo01とか02とか使われていないらしいカラムがあったのでそれを使うことにする。

1:管理画面のテンプレートを編集
data/Smarty/templates/admin/basis/payment_input.tpl
テーブルの行をひとつ追加
[html]
<tr>
<th>説明</th>
<!–{assign var=key value=”memo01″}–>
<td><textarea name=”<!–{$key}–>” cols=”60″ rows=”5″><!–{$arrForm[$key].value}–></textarea></td>
</tr>
[/html]

2:対象クラスを拡張
data/class_extends/pages/admin/basis/LC_Page_Admin_Basis_PaymentInput_Ex.php
フォームの内容を追加するためlfInitParamをオーバーライド
[PHP]function lfInitParam($mode, &$objFormParam) {
parent::lfInitParam($mode,$objFormParam);
$objFormParam->addParam(“説明”, “memo01”, STEXT_LEN, ‘KVa’, array(“SPTAB_CHECK”, “MAX_LENGTH_CHECK”));
}[/PHP]

3:公開側のテンプレートを編集
data/Smarty/templates/default/shopping/payment.tmpl
[html]
<!–{section name=cnt loop=$arrPayment}–>
<!–{$arrPayment[cnt].payment_memo01|h}–>
<!–{/section}–>
[/html]
※section ってよくわからないな。。foreachにしたい。。

4:データベースから値を持ってくるようにHelper_Purchase_Exクラスを編集
data/class_extends/helper_extends/SC_Helper_Purchase_Ex.php
getPaymentsByPriceをオーバーライドし、クエリにmemo01も入れるようにする
[php]
function getPaymentsByPrice($total,$deliv_id){
//省略
$payments = $objQuery->select(“payment_id, payment_method, rule, upper_rule, note, payment_image, charge, memo01”, “dtb_payment”, $where, $arrPaymentIds);
//省略
}[/php]

EC-CUBE2.11(session_set_save_handler)+Ajaxでセッションがうまくいかない件。

2日悩んでまだうまくいっていないことですが、とりあえずこれまでわかったことをメモします。
※この情報は間違っている可能性が高いです。

EC-CUBEでは2.11ではセッション情報をデータベースに保存している。
通常、商品をカートに入れる際にはカートのページにリダイレクトされ、セッション情報にカートの内容が保存される。

カートの追加をAjaxで実装したところ、連続して複数の商品をカートに追加すると、タイミングによってカートに追加されない商品があるという現象が起きた。EC-CUBE2.11ではSC_Helper_Sessionクラスにてsession_set_save_handlerが呼ばれ、セッションに対して起こるイベント用のようなものが定義されて、オリジナルの処理(データベースへセッション情報を書く処理)がかかれている。

こうすることによって単純に$_SESSIONにプロパティをセットするだけでデータベースにセッション情報を残すことができる。

原因を探っていくと、どうやら$_SESSIONを操作した際に、その都度登録した処理(データベースへ書き込む処理)が呼ばれるわけではないことで、たとえばその処理の中で一度$_SESSIONを読み込み、それに対して何かを付けたし、そして再度$_SESSIONに書き込むというような処理を入れることが原因のようだ。

EC-CUBEではカートにある商品をID(連番の)で処理しているようなのだが、次の商品がカートに追加されるたびに一番最後のID(数字)に1を足して処理している。そのためカートに追加する際に一度カートの内容を読み込み、追加し、書き込むという処理をする。

Ajaxを使うことで「読み込み」「読み込み」「書き込み」という処理がありえるので、商品が0のときは「次はID:1」「次もID:1」「IDが二つかぶるので2つめのみ追加」となる。

通常は「読み込み」から「書き込み」まで同じ行に対する処理をロックできるので問題は起こらないのだが、読み込みは読み込み、書き込みは書き込みとデータベースへのアクセスが別々になっていることでこのようなことになってしまっている模様。

その辺のトランザクションを何とかするか。セッションを連番で処理するのを何とかするか。

どうすれば最善か。まだ考察中です。

追記(2011/11/10)

Ajaxを使うことで「読み込み」「読み込み」「書き込み」という処理がありえるので、商品が0のときは「次はID:1」「次もID:1」「IDが二つかぶるので2つめのみ追加」となる。

さらに調査した結果、こういうことではないようだ。

IDがかぶるから上書きされるのではなく、セッションが書き込まれるときには
「すべてを読み込み」→「変更(追加)」→「すべてを書き込み」となるので、
たとえばAが入っているセッションにB,Cを書き込みたい場合
「A」を読み込んでそれに「B」を足して「A,B」となり、それを書き込む前に「A」を読み込み「C」を足して「A,C」となり、最終的に「A,C」となってしまうということらしい。

これはsession_set_save_handlerでデータベースを使う際にまれにある現象らしい。
http://xoops.ec-cube.net/modules/newbb/viewtopic.php?viewmode=thread&topic_id=8247&forum=2&post_id=39923#forumpost39923
http://svn.ec-cube.net/open_trac/ticket/571

追記2(2011/11/11)

結局、非同期通信を行う場合、session_set_save_handlerを使うと読み込みと書き込みが入れ子になり、上記のような現象になることは避けられなかった。

また、Ajax側で通信を順番に行うようにすることでこれを回避することができた。
具体的には商品をaddしたときにqueueに追加し、順番に処理していく。

また処理が終わったらカートをリフレッシュしていたのだが、コレもまずかった。

カートのリフレッシュ時には当然最新のカートの情報を取得するのだが、それもこの現象の原因になった。
つまり読み込むだけであっても通信が入れ子になることでセッションの同期が取れず、セッション関連がある通信は常に順番に確実に行う必要がある。

session_set_save_handlerを使用しないような実装も考えたが、EC-CUBEの保守がややこしいことになりそうなのでやめた。

通信をすべて順番に行うことで、問題を解決することにした。

  1. 商品を追加ボタンを押す
  2. queueに追加
  3. queueがひとつだけならqueueを開始
  4. ajaxでpost
  5. javascriptでカートに追加中の表示(追加ボタンをロード中にし、カートに商品を半透明で追加表示)
  6. 応答があったら本当にカートに入っているかを一度チェックする
  7. 成功ならカートに追加済みの表示:失敗ならすべてを元に戻す。
  8. queueがまだあるなら次のqueueを開始し、4へ戻る。

追記3(2011/11/11)

resize_image.phpを動かすと、セッションが上書きされるようだ。なんで、画像をリサイズするためにセッションを操作しているのか不明。。
なんだか動作ももたつくので使用するのをやめた。

EC-CUBE2.11 静的URLにしたらソートができなくなった。

こちらのページ参考に商品詳細ページとリストページを静的URLにしたのですが、その影響でリストページがソートされなくなった。

調べてみると、どうやら
data/class/pages/products/LC_page_products_list.php

$this->arrForm = $_REQUEST;//時間が無いのでコレで勘弁してください。 tao_s
が影響している模様。

.htaccessを以下のように書き換えた。

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
#RewriteRule ^detail([0-9]+).html+ detail.php?product_id=$1 [L]
RewriteRule ^detail([0-9]+).html+ detail.php?product_id=$1&%{QUERY_STRING} [L]
#RewriteRule ^list([0-9]+).html+ list.php?category_id=$1 [L]
RewriteRule ^list([0-9]+).html+ list.php?category_id=$1&%{QUERY_STRING} [L]

EC-CUBE 2.11 詳細ページをlightbox風に表示する

詳細ページなどをAjaxを使ってiframeで表示したいとき、共通のheader,footerを表示したくなかった。
でも管理画面のページレイアウト詳細設定で「共通のヘッダーを使用する」と「共通のフッターを使用する」のチェックボックスをはずしてしまうと、iframeで表示しない場合も表示されなくなってしまうので、iframeでの表示と通常の表示とで、読み込むヘッダーとフッタを変更したい。

1:まず
data/class_extends/SC_View_Ex.php
のassignTemplatePath()をオーバーライド
header_tpl_for_iframeとfooter_tpl_for_iframeとしてheader_iframe.tplとfooter_iframe.tplを新規で定義
[PHP]
function assignTemplatePath($device_type_id) {
parent::assignTemplatePath($device_type_id);
$templatePath = SC_Helper_PageLayout_Ex::getTemplatePath($device_type_id);
$header_tpl_for_iframe = $templatePath . “header_iframe.tpl”;
$footer_tpl_for_iframe = $templatePath . “footer_iframe.tpl”;

$this->assign(“header_tpl_for_iframe”, $header_tpl_for_iframe);
$this->assign(“footer_tpl_for_iframe”, $footer_tpl_for_iframe);
}

[/PHP]

2:該当するクラス(今回の場合は詳細ページなので)
data/class_extends/page_extends/products/LC_Page_Products_Detail_Ex.php
のprocessをオーバーライドし、arrPageLayoutにisIframeプロパティを追加。
クエリにdisplayMode=iframeとなっていたときにtrueに設定。

[PHP]
function process() {
$this->arrPageLayout[“isIframe”] = $this->getDisplayMode() == “iframe” ;
parent::process();
}
[/PHP]

displayModeはほかでも遣う気がしたのでページクラスを拡張
data/class_extends/page_extends/LC_Page_Ex.php
[PHP]
function getDisplayMode() {
$pattern = ‘/^[a-zA-Z0-9_]+$/’;
$mode = null;
if (isset($_GET[‘displayMode’]) && preg_match($pattern, $_GET[‘displayMode’])) {
$mode =  $_GET[‘displayMode’];
} elseif (isset($_POST[‘displayMode’]) && preg_match($pattern, $_POST[‘displayMode’])) {
$mode = $_POST[‘displayMode’];
}
return $mode;
}
[/PHP]

3:メインテンプレート
data/Smarty/default/site_main.tpl
にヘッダーとフッターを読み込むところがあるので分岐する。
[PHP]
<!–{if $arrPageLayout.isIframe}–>
<!–{include file= $header_tpl_for_iframe}–>
<!–{else}–>
<!–{include file= $header_tpl}–>
<!–{/if}–>
[/PHP]
[PHP]
<!–{if $arrPageLayout.isIframe}–>
<!–{include file= $footer_tpl_for_iframe}–>
<!–{else}–>
<!–{include file= $footer_tpl}–>
<!–{/if}–>
[/PHP]

4:読み込む専用のヘッダーとフッターを追加する
data/Smarty/default/header_iframe.tpl
data/Smarty/default/footer_iframe.tpl

5:html/products/.htaccessの内容を変更する。※!詳細ページを静的にしていない場合は必要ないです。
こちらのページを参考に詳細ページを静的URLにしていたので下記のように記述していたんですが、
RewriteRule ^detail([0-9]+).html+ detail.php?product_id=$1 [L]
これだURLのクエリ情報が付与されなかったため下記のように変更。
RewriteRule ^detail([0-9]+).html+ detail.php?product_id=$1&%{QUERY_STRING} [L]

*追記 2011/11/31
この記事関係のない部分で別の問題もあったので最終的に.htaccessはこうなった

6:lightbox的に表示したいのでプロダクトリストを編集する。今回はcolorboxを使用。
data/Smarty/default/products/list.tpl
jqueryとcolorboxを読み込んでおく。
[JAVASCRIPT]
$(document).ready(function() {
var colorbox_ajax = $(“.colorbox_ajax”);
$(“.colorbox_ajax”).each(function(){
var href = $(this).attr(“href”);
href += “?displayMode=iframe”;
$(this).attr(“href”,href);
});
$(“.colorbox_ajax”).colorbox({ width: “960px”, height: “420px”,iframe: true});
});
[/JAVASCRIPT]
[HTML]
<a href=”<!–{$smarty.const.P_DETAIL_URLPATH}–><!–{$arrProduct.product_id|u}–>.html” class=”colorbox_ajax”>product name</a>
[/HTML]
aタグのhrefには記述せず(直接来た場合はiframeじゃない版を表示したいので)、わざわざjqueryでループし、displayModeを付与した。

EC-CUBE 2.11 追加したカートのセッション情報を注文完了時に消しておく

/data/class_extends/helper_extends/SC_Helper_Purchase_Ex.php
cleanupSessionをオーバーライド
[PHP]
function cleanupSession($orderId, &$objCartSession, &$objCustomer, $cartKey) {
$objCartSession->delAllAdditionalInfo();
parent::cleanupSession($orderId, $objCartSession, $objCustomer, $cartKey);
}
[/PHP]

EC-CUBE 2.11 合計金額に基本料金を追加

あらかじめ基本料金を基本情報として追加しておく

合計金額に基本料金を追加する。
/data/class_extends/SC_CartSession_Ex.php

[PHP]
function calculate($productTypeId, &$objCustomer, $use_point = 0,
$deliv_pref = “”, $charge = 0, $discount = 0, $deliv_id = 0) {
$results = parent::calculate($productTypeId, $objCustomer, $use_point, $deliv_pref, $charge, $discount, $deliv_id);

$objDb = new SC_Helper_DB_Ex();
$col    = SC_Utils_Ex::sfGetCommaList(array(“basic_fee”));
$arrRet = $objDb->sfGetBasisData(true, $col);
$results[‘basic_fee’] = $arrRet[“basic_fee”];
$results[‘payment_total’] += $results[‘basic_fee’];

return $results;
}

[/PHP]

 

追記(2011/11/17)

culculateではなくて、getAllProductsTotalメソッド内で行ったほうがよさそうということで、変更しました。

[PHP]
function calculate($productTypeId, &$objCustomer, $use_point = 0,
$deliv_pref = “”, $charge = 0, $discount = 0, $deliv_id = 0) {
$results = parent::calculate($productTypeId, $objCustomer, $use_point, $deliv_pref, $charge, $discount, $deliv_id);

$objDb = new SC_Helper_DB_Ex();
$col    = SC_Utils_Ex::sfGetCommaList(array(“basic_fee”));
$arrRet = $objDb->sfGetBasisData(true, $col);
$results[‘basic_fee’] = $arrRet[“basic_fee”];
//$results[‘payment_total’] += $results[‘basic_fee’];

return $results;
}
function getAllProductsTotal($productTypeId) {
//省略

//基本料金を追加
$objDb = new SC_Helper_DB_Ex();
$col    = SC_Utils_Ex::sfGetCommaList(array(“basic_fee”));
$arrRet = $objDb->sfGetBasisData(true, $col);
$total += $arrRet[“basic_fee”];

return $total;
}

[/PHP]

 

EC-CUBE 2.11 基本情報追加メモ

1:データベースdtb_baseinfoに項目を追加

2:data/class_extends/page_extends/admin/basis/LC_Page_Admin_Basis_Ex.phpを編集
[php]
// 追加項目
function lfGetCol() {
$arrCol = parent::lfGetCol();
$arrCol[] = “basic_fee”;
return $arrCol;
}
function lfInitParam(&$objFormParam, $post) {
parent::lfInitParam($objFormParam, $post);
$objFormParam->addParam(“基本料金”, “basic_fee”, PRICE_LEN, ‘n’, array(“NUM_CHECK”, “MAX_LENGTH_CHECK”));
}
[/php]
※この例は基本料金(basic_fee)を追加した。

3:管理画面のテンプレートを編集
data/Smarty/templates/admin/basis/index.tpl
[php]
<tr>
<th>基本料金<span> *</span></th>
<td>
<span><!–{$arrErr.basic_fee}–></span>
<input type=”text” name=”basic_fee” value=”<!–{$arrForm.basic_fee|h}–>” maxlength=”<!–{$smarty.const.PRICE_LEN}–>” size=”6″ style=”<!–{if $arrErr.basic_fee != “”}–>background-color: <!–{$smarty.const.ERR_COLOR}–>;<!–{/if}–>” /> 円
</td>
</tr>
[/php]

EC-CUBE:2.11 カスタマー情報の追加メモ

1:データベース:dtb_customerに必要な項目を追加

2:それらの項目にセレクトボックスなどの配列情報があればマスターデータも用意する。マスターデータのテーブルは[mtb_]で始まるテーブルとして設置。

3:下記、拡張クラスのfunction init()の中で新しい変数を設定し追加したマスターデータを代入しておく。

  • data/class_extends/page_extends/admin/customer/LC_Page_Admin_Customer_Edit_Ex.php
  • data/class_extends/page_extends/admin/customer/LC_Page_Admin_Customer_Ex.php
  • data/class_extends/page_extends/admin/mail/LC_Page_Admin_Mail_Ex.php
  • data/class_extends/page_extends/admin/total/LC_Page_Admin_Total_Ex.php
  • data/class_extends/page_extends/entry/LC_Page_Entry_Ex.php
  • data/class_extends/page_extends/mypage/LC_Page_Mypage_Change_Ex.php
  • data/class_extends/page_extends/shopping/LC_Page_Shopping_Ex.php

[php]
function init() {
parent::init();
$masterData = new SC_DB_MasterData_Ex();
$this->[任意の編集名:例:arrHeight] = $masterData->getMasterData(“[追加したマスタデータテーブル名:例:mtb_height]”);
}
[/php]

4:テンプレートを修正する

  • /data/Smarty/templates/default/frontparts/form_personal_input.tpl
  • /data/Smarty/templates/admin/customer/edit.tpl

[php]
<!–{if $flgFields > 1}–>
<tr>
<th>[タイトル:例:身長]<span>※</span></th>
<td>
<!–{assign var=key1 value=”`$prefix`[キーとなる変数:例:height]”}–>
<!–{if $arrErr[$key1]}–>
<div><!–{$arrErr[$key1]}–></div>
<!–{/if}–>
<select name=”<!–{$key1}–>”>
<option value=”” selected=”selected”>身長を選択</option>
<!–{html_options options=[マスターテーブルの変数名:例:$arrHeight] selected=$arrForm[$key1]}–>
</select>
</td>
</tr>
<!–{/if}–>
[/php]

  • /data/Smarty/templates/default/entry/confirm.tpl
  • /data/Smarty/templates/admin/customer/edit_confirm.tpl
  • /data/Smarty/templates/default/mypage/change_confirm.tpl
  • /data/Smarty/templates/default/shopping/confirm.tpl
  • /data/Smarty/templates/default/mail_templates/order_mail.tpl

[php]
<tr>
<th>[タイトル:例:身長]<span>※</span></th>
<td>
<!–{$arrForm.[変数名:例:height]|h}–>
</td>
</tr>
[/php]

5:データチェックを追加する。データチェックのヘルパークラスの拡張クラスにファンクションを追加する。
/data/class_extends/helper_extends/SC_Helper_Customer_Ex.php
sfCustomerCommonParam()をオーバーライドし、ファンクションsfCustomerCommonParamEx()を追加で呼ぶようにする。
[php]
function sfCustomerCommonParam (&$objFormParam) {
parent::sfCustomerCommonParam($objFormParam);
SC_Helper_Customer_Ex::sfCustomerCommonParamEx($objFormParam);
}

function sfCustomerCommonParamEx (&$objFormParam) {
//カスタマイズここから
$objFormParam->addParam(“身長”, ‘height’, STEXT_LEN, ‘n’, array(“EXIST_CHECK”, “SPTAB_CHECK”, “MAX_LENGTH_CHECK”));
//カスタマイズココまで
}
[/php]