2016年12月4日

カラーミーいじりたおしでよく読まれた記事

12月というのは、買い物したくなる季節ですね。私もなんやかんやと物色しています。
プレゼントもそうですが、家のこまごまとした備品を新しくしたくなります。

「カラーミーいじりたおし」も再出発すべく、新サイトの準備を進めています。
全体的に古くなった記事・コーディングも多く、文字サイズは小さいしWebデザインも古いので、全部作りなおす予定です(徐々にですが)。

さて、ここでの99記事目で、総集編的な内容となっています。
今回は、これまで書いた記事で特に読まれた物を、順にご紹介させていただきます。


1. 最近の流行、集客を考えた新しいカートのかたち


>>「カートに入れるボタンを商品詳細ページ以外に設置する」 2010/08/21

同様のことがより簡単にできる、「どこでもカラーミー」(カートJS機能)が実装されて、いまでは古い記事になりました。
流行は最近ですが、 昔から興味を持って読まれていたのでしょうね。

先日のカラーミー公式のECコラム「WordPress・Tumblrで制作したサイトにカートを設置!「メディアEC」デザイン事例10選」でも取り上げられていましたが、昨今どこでもカラーミーでカートを付けるお店をちらほら見かけるようになりました。

具体的には、商品ページ以外の部分(興味を持ってもらえるコンテンツ)を頑張って充実させて、集客に役立てているお店でしょうか。

・関連記事
カートJS機能について 2011/08/17
カートJS機能を実践的にいじる 2014/04/26


2. カラーミーショップAPI


>>カラーミーAPIを試してみた 2」 2014/03/27

カラーミーショップの特徴でもあります。無料で使えて、商品、顧客、受注データベースなどを読んだり書いたりできます。
参照「カラーミーショップAPIドキュメント

何に使うのかというと、 お店の業務に合わせたアプリケーションの開発が可能で、これまで手動でやっていたことを自動にしたり(業務の効率化)。
Webショップ上に必要な情報を取ってきて表示したりできます(ショップの機能面)。例えば、楽天でみかける注文速報のような機能とか。
 
・関連記事
カラーミーAPIを試してみた 1 2014/03/26
カラーミーAPIを試してみた 2 2014/03/27
カラーミーAPI実践編1 データ抽出 2014/04/10
カラーミーAPI実践編2 ポイント表示 2014/04/16
カラーミーでウィッシュリストを作る - カラーミーショップAPI編 2015/06/26


3. カラーミーのできないことの判断は難しい


>>カラーミーにできること、できないこと」 2010/05/13

カラーミーに最初から実装されていないとユーザーではどうしようもないことも多いです。
参照「機能一覧 - カラーミーショップ ネットショップ運営サービス

上述ページではざっくりとした紹介ですので、その上でユーザー側でなにができるのか。
JavaScript(jQuery)、PHPやカラーミーショップAPIなどで自前で機能面を強化できます。
「これはカラーミーではできません」と言うには、上述の広範な知識が必要です(自由度が高いんですね)。
この記事は重要だと思いながらも、更新が止まっていました。

デザイン面では、HTML/CSSにより多くの部分がカスタマイズ可能です。


4. ほしい物リストを付ける


>>ほしい物リストを作る 1」 2010/08/22

いまらなら、カラーミーショップAPIを使ってやるところです。
カラーミーショップAPIがない、Jugem Cartでは、こういうやり方で実装できます。

・関連記事
ほしい物リストを作る 1 2010/08/22
ほしい物リストを作る 2 2010/08/29
ほしい物リストを作る 3 2010/08/29
ほしい物リストを作る 4 2010/08/29
カラーミーでウィッシュリストを作る - カラーミーショップAPI編 2015/06/26


5. 実は、カートを二か所につけることができる


>>カートに入れるを二ヶ所につける 1」 2010/05/24
 
商品詳細ページの上下に配置することを想定しています。たくさんスクロールするページのときに有効です。
記事とはすこし話が違いますが、商品説明の下に「組合せ購入パターン」で作成した商品を表示している場合などは、そこにも「カートに入れる」ボタンを設置することができます(ページに移動せずにカートに入れられる)。

・関連記事
カートに入れるを二ヶ所につける 1 2010/05/24
カートに入れるを二ヶ所につける 2 2010/05/25
カートに入れるを二ヶ所につける 3 2010/05/26
カートに入れるを二ヶ所につける - オプション編 2014/04/26


6. Smarty?なにそれ


>>Smartyサンプル 1」 2010/06/02
ネット上に資料が少ないことも理由でしょうか。ヒットしやすいみたいです。
カラーミーショップで使う分には例文さえあれば十分かなと思います。

・関連記事
Smartyサンプル 1 2010/06/02
Smartyサンプル 2 2010/06/04 
カラーミーショップにおけるSmarty入門 2016/03/06 


7. その他


>>テンプレート共通部分を表示させない方法」 2011/07/26
これもSmartyを使った機能です。

>>カラーミーの商品並び順」 2010/05/14
価格の高い順にソートができません。これは今でもそうです。
商品名のソートもありません。


2016年10月6日

最近、カラーミーショップで発生したスパムメールの話

カラーミーショップのお知らせに、「mail02.shop-pro.jpのメールサーバーでメールが届かない事象が発生しております」というタイトルで障害情報があがっています。

私のお手伝いしているショップ様も似たような状況に陥っていて、私もその件について調べました。
ちなみに、私が調べたショップ様は別のメールサーバーですので、似たような状況が他ショップ様でも発生しているのだと、この障害情報で知りました。
状況は障害情報に載っている内容とほとんど同じでしょうか。

遭遇した状況は下記の通り。
発生時期 先週末から
状況 メール未着のエラーメールが山盛り
不具合 メールが届いていないとお客様から連絡がくる
1分で10件くらいエラーメールがきました。しばらくすると、カラーミーショップから連絡がきて、メールアカウントがロックされます(ロック解除はすぐできます)。

障害情報には「当該メールサーバーから、大量メール配信を行っているアカウントがあり」とあります(エラーメールもメール配信になるのでしょう)。

メールアカウントのパスワードを変更してもエラーメールが止まりませんので、パスワードが抜かれたのではないと考えられます(PCのウィルスチェック済み)。

そうだとしたら、スパム業者にお店のメールアドレスをFromに使用されているのだろうと考えられます(送信元の偽装は簡単です)。たったそれだけで、こんなひどい目に。

ネットで資料を見ていると、エラーメールの正当性を検証する方法もあるようで、そういう機能がないと抜本的な解決には至らないように思います。

カラーミーショップによると「順次調査および対応を実施しております」ということですので、今後の対応については気になるところです。

【追記】
メールアドレスを作り直しましたが、Gmail宛は迷惑メールフォルダに振り分けられてしまう事態に。
仕方ないので、別ドメインのメールアドレスを使うことに。

2016年9月3日

再入荷お知らせメールの話3


前回からの引き続きで、再入荷お知らせメールの話3。
今回は入力フォームのサンプルを作ってみました。

「初めてのPHP5(オライリー本)」のコードを参照しました(解説はオライリー本参照)。
PHP入門書には、この手の入力フォームのコードが載っていますので、読み解きやすいものを選ばれると良いでしょう。

入力画面→入力項目のチェック→登録
↑     ↓エラー
↑←←←←←↓


私が行ったテストはソースコードレビューのみで、他はほとんど行っていません。
本番環境に実装する場合には、ご自身の責任でしっかりとテストを行ってください(ソフトウェアテストについて理解しておく必要があります)。


1. コーディング(人柱版)

<?php

if (isset($_POST['_submit_check']) && $_POST['_submit_check']) {
  if ($form_errors = validate_form()) {
    show_form($form_errors);
  } else {
    process_form();
  }
} else {
  if(! isset($_GET['pid'])) {
    $_POST['pid'] = '';
  } else {
    $_POST['pid'] = $_GET['pid'];
  }
  if(! isset($_POST['mail'])) {
    $_POST['mail'] = '';
  }
  show_form();//最初の画面表示
}


function show_form($errors = '') {
  if ($errors) {
    $error_text = implode('<br/>',$errors);
  } else {
    $error_text ='';
  }

?>

<!--入力画面-->
<form method="POST" action="<?php print $_SERVER['SCRIPT_NAME']; ?>">
  <input type="text" name="mail" value="<?php print htmlentities($_POST['mail']) ?>" />
  <input type="hidden" name="pid" value="<?php print htmlentities($_POST['pid']) ?>" />
  <input type="hidden" name="_submit_check" value="1" />
  <input type="submit" value="登録する" />
</form>

<?php

  print $error_text;
}


function validate_form() {
  $errors = array();
  if (! strlen(trim($_POST['mail']))) {
    $errors[] = 'メールアドレス未入力エラー';
  } elseif (! preg_match('/^[^@\s]+@([-a-z0-9]+\.)+[a-z]{2,}$/i', $_POST['mail'])) {
    $errors[] = 'メールアドレス構文エラー';
  }
  if (! strlen(trim($_POST['pid']))) {
    //正規のリンクから呼び出されていないのでトップに飛ばすなりする
    $errors[] = '商品ID未入力エラー';
  } elseif(! is_numeric($_POST['pid'])) {
    //正規のリンクから呼び出されていないのでトップに飛ばすなりする
    $errors[] = '商品ID数字エラー';
  }
  //商品IDがカラーミーショップに存在しているか
  //pidとmailの組み合わせが、既に登録されていないか
  //在庫はゼロかなどをチェック

  return $errors;
}


function process_form() {
  //データベース登録
  $dsn = 'mysql:dbname=mydb;host=localhost';
  $user = 'root';
  $password = '';

  try{
    $pdo = new PDO($dsn, $user, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

    $sql = 'INSERT INTO restock SET pid=?, mail=?';
    $stmt = $pdo->prepare($sql);
    $stmt->execute(array($_POST['pid'], $_POST['mail']));
  } catch (PDOException $e){
    //print('Error:'.$e->getMessage());
    die();
  }

  //登録完了画面
print <<<_HTML_
登録ありがとうございました。<br/>
_HTML_;



  exit();
}
?>

2. 簡単な説明


ウィンドウ(or モーダルウィンドウ)で入力フォームを開くと良さげ、閉じるボタンも付けて。その他、デザイン的な体裁を整える必要があります。

表示させたい項目があれば、カラーミーショップAPIで取ってくる。

isset()がないと、最初の画面表示でNoticeが出るので。

メールアドレス構文チェックの正規表現も「初めてのPHP5(オライリー本)」から。検索すると、たくさん例文が見つかりますが、どれがよいのやら。

pidのエラーは明らかにオカシイので、入力画面に戻さず、トップページに飛ばすなりする。

htmlentities箇所は定番の、htmlspecialchars($str, ENT_QUOTES, 'UTF-8')でよいかと。

CSRF対策をしていません(IPAの「安全なウェブサイトの作り方」参照)。
ログイン不要の入力フォームの場合はもともといたずらし放題なので、トークンのやりとりをしないアプリケーションも見かけます(焼け石に水という考え方だと思います)。
今回サンプルとして作ったコードも、他人のメールアドレスを入力して登録できる仕組みなので、考え方も弱点も似たようなものです。
ただ、本番環境で動かすなら、わずかな問題でも対応するのがよい開発者。検索すると、トークンのやりとりで対策するサンプルが見つかります。

いたずら対策として、カラーミーショップのアカウントにログインするよう促して、そこからメールアドレスを取ってくるか(アカウント登録が必須になる)。
あと、CAPTCHAつけたり。

登録メール宛に内容を送信し、リンクをクリックしたのちに登録するような仕組みにするか(登録に手間がかかって嫌かもしれないが)。認証コードを送信して、入力してもらうか。


3. おわりに 


省略箇所もありますので、のこりを自分で仕上げられる人用です

この手のウェブアプリケーションでもっとも気を遣う点は、セキュリティだと思います(知識をインプットしておかないと、なにをどこまでがわからない)。
IPAの「安全なウェブサイトの作り方」が読みやすくて、入門編として勉強になりました(同ページ内の「安全なSQLの呼び出し方」もチェック)。
引き続き、ウェブや書籍でインプットしていきたいと思います。

【追記】
時折見かけますが、クエリパラメータをディレクトリ風にして渡すこともできます。興味あれば、検索してみてください。

【追記2】
徳丸浩さん著の「体系的に学ぶ安全なWebアプリケーションの作り方」を読みましたが、大変分かりやすかったです。これは手元に置いておきたい。

2016年8月27日

再入荷お知らせメールの話2

再入荷お知らせメールの話の続き。

前回は、お客様が手軽にメール送信するだけの機能について、簡単に設置してみました。
メールを受けて→メモって→入荷メールを送信、と大部分を手動で運用する仕組みで、導入も簡単&知識もそれほど不要で、個人的にはおすすめです。

レンタルサーバーにデータベースを持つことで、手動で行っていた部分をPHPのプログラムに代行させることも可能です(前回と比べるとハードルが上がります)。
今回はそのあたりの説明と、コーディングについて書きます。

PHPとデータベース周りについては、この記事では解説していません。
ウェブアプリケーション構築においては、セキュリティ面も気を配る必要があります。
検索して調べるか書籍をあたって、慎重に検討してください。

動作テストは簡単にしか行っていません。
本番環境に実装する場合には、ご自身の責任でしっかりとテストを行ってください(ソフトウェアテストについて理解しておく必要があります)。


0. 仕様と留意点について


データベースにすでに登録されているという前提です(カラムは、id(連番)、pid(商品ID)、mail(お客様メール))。
登録フォームは、ご自分で用意ください。入力時の在庫ゼロチェック、登録のダブりチェック、登録メールアドレスのバリデーションなどをやっておく必要があります。


今回のコーディングは、カラーミーショップの更新をチェックし、データベース(MySQL)からデータを取得し、メール送信する部分です。

カラーミーショップAPIのみで「再入荷した商品」という判断をすることは、現状無理です。ドキュメントによると、都合よさそうなリクエストパラメータがありません。
仕方ないので、カラーミーショップAPIで、今日の更新データを取ってきて、在庫>0の商品IDを抽出しています。

この条件で「再入荷した商品」を抽出したというには、ちょっとまずいです。
たとえば、販売して在庫が5→4に減った場合、商品登録でコメントやその他項目などを更新した場合など、「再入荷したので在庫を増やした」以外の更新をたくさん含んでいます。
ただ、データベース登録時の在庫ゼロチェックがきちんされていれば、データベース検索時に「再入荷した商品」と無関係な商品は(たぶん)除外されます。


じゃぁそれでOKかというと、そうでもなくて。
サーバーに負荷をかけないためにも、明らかに不要な分は先に除外する方向で運用を決めたほうがよいと思います。
また、カラーミーショップAPIはリクエスト一回当たり最大50件なので、それより件数が多いと、複数回に分けてリクエストする必要があります(処理を追加する必要がありますし、リクエストも連投しすぎると制限がかかります)。
この点も考慮する必要が出てくるかもしれません。

お店の運用で再入荷商品であるとわかるような工夫して、条件に追加してやるのがベターだと思います(良い案もないので、ある程度の妥協は必要です)。
商品名につける、空き項目につける、再入荷カテゴリーに移動する、ここは手動にするなど。


今回のコーディングについての留意点。
「データベースに登録が0件だった場合は即終了」を追加すべきです(省略しています)。
エラー処理もろもろ、お客様にメール送信しましたよという報告メール、オプション在庫の対応、ヒットする件数が多い場合の追加処理、送信済みフラグを立てるのか、データベースから削除するタイミング、メール内容をきっちり作成、複数商品入荷した場合はメールをまとめる、メール送信規制の回避、などお店の事情で検討して、機能追加してください。


1. コーディング(人柱版)

<?php
//カラーミー
header("Content-Type:text/html; charset=UTF-8");//文字化け対策
$request_options = array(
    'http' => array(
        'method'  => 'GET',
        'header'=> "Authorization: Bearer xxxxxxxxxxxxxxx\r\n"
    )
);
$context = stream_context_create($request_options);
$url = 'https://api.shop-pro.jp/v1/products.json?limit=50&update_date_min=' . date('Y-m-d');
$response_body = file_get_contents($url, false, $context);
$response_json = json_decode($response_body, true);

//抽出、降順でソートしておくと処理が減らせる
for($i=0; $i<count($response_json['products']); $i++){
    if($response_json['products'][$i]['stocks'] > 0) $data[] = $response_json['products'][$i]['id'];
}

//データベース
$dsn = 'mysql:dbname=mydb;host=hostname';
$user = 'username';
$password = 'password';

try{
    $pdo = new PDO($dsn, $user, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

    for($i=0; $i<count($data); $i++){
        $sql = 'SELECT DISTINCT mail FROM restock WHERE pid=?';
        $stmt = $pdo->prepare($sql);
        $stmt->execute(array($data[$i]));
        foreach ($stmt as $row) {
            //メール送信
            mb_language("Japanese");
            mb_internal_encoding("UTF-8");
            $to = $row['mail'];
            $subject = 'SUBJECT';
            $message = $data[$i];
            $headers = 'From: shop@example.co.jp' . "\r\n". 'Return-Path: shop@example.co.jp';
            $send_mail=mb_send_mail($to, $subject, $message, $headers);

            if ($send_mail) {
                $sql = 'DELETE FROM restock WHERE pid=? AND mail=?';
                $stmt = $pdo->prepare($sql);
                $stmt->execute(array($data[$i], $row['mail']));
            } else {
                //エラー処理
            }
        }
    }
} catch (PDOException $e){
    //print('Error:'.$e->getMessage());
    die();
}


2. おわりに 


このあたりで、作業の半分くらいだと思います。
私は試しに作っただけで、実装する予定はありません。 のこり半分を自分で仕上げられる人用です
バグ報告していただけると、私が喜びます。

ソフトウェアテストも、コーディングと同様に大事な技術になります。
十分なインプットが必要です。

cronで自動実行する予定です(レンタルサーバー次第)。

XAMPPを使ってメール送信のテストをする場合は、事前に設定が必要です。
検索して調べてください。

再入荷お知らせメールの話3」につづきます。

[追記]
PHPやPHPセキュリティの入門書によると、(フォーム入力時に当然バリデーションしてから登録するのですが)データベースの登録内容も無条件に信用せずに、データをあらためてバリデーションするくらいの丁寧な仕事が必要だそうだ(カラーミーショップAPIも含む)。
pid、mail、その他データベースからの項目もチェックする姿勢で臨むほうがよいと考えます。

2016年8月21日

再入荷お知らせメールの話

カラーミーいじりたおしの記事数が95(100目前!)になりました。
純粋に”それ”が好きってだけでここまで来ましたが、好きを超えるモチベーションというものも、なかなか見つからないものです。私は、わりと幸せだなぁと感じます。
カラーミーショップでお店をされている方でも、似たような想いで、仕事をされてる方も多いのではないでしょうか。


さて、本日の話題はこれ。
「再入荷お知らせ」「入荷連絡メール」「再入荷連絡メール」「再販売お知らせメール」、カートによって色々な呼び方があります、あれです。
 
カラーミーショップにはなぜかついていない「再入荷お知らせメール」機能、カラーミー七不思議のひとつ。
「この商品について問い合わせる」リンクがありますので、それを代用していらっしゃるお店もあるかと思います。
そのほかには、オプションボタン、チェックボックスを設置するために、新しく問い合わせフォームを作って、レンタルサーバーに置いているお店もあります。

カラーミーショップ的にどんなことができるでしょうか。機能設置について、検討してみました。
先に書きますが、今回のはあまり役に立たないコードになっています。


0. 一般的な「再入荷お知らせ」機能の流れ


登録部分
  1. 商品詳細ページのリンクをクリックする
  2. 入力フォームが開く
  3. メールアドレスを入力する
  4. OKボタンで、登録完了メールを送信
  5. データベースに追加

入荷連絡部分
  1. 在庫0から増加したら、メール送信


いくつかのカートを見てみましたが、傾向としては、
  • 登録はできるが、削除する方法は実装されていない
  • アカウントと紐づいていない(誰でも登録できる)
  • 在庫チェック・メール送信は一定時間毎


処理で一番考える必要があるのは入荷連絡部分。
仕様を細かく決めて、例外を丁寧に作りこむ必要もあります。
自前でデータベースを持つと、バックアップなどのサーバー運用と、サーバー障害時の対応も考えておく必要があります。

以上を踏まえて、楽に作れる範囲まででコードを書いてみました。
登録数が少なければ、これくらいでもいいかなと思います。
今回の仕様説明は、コードの次に書いてあります。


1. コード


商品詳細ページ
<form action="http://php.example.jp/sendMail.php" method="POST" name="form1">
  <input type="hidden" name="pid" value=<{$product.id}>>
  <input type="hidden" name="id" value=<{$members_id}>>
  <a href="#" onClick="document.form1.submit();">入荷したら連絡</a>
</form>    

sendMail.php
<?php
$request_options = array(
    'http' => array(
        'method'  => 'GET',
        'header'  => "Authorization: Bearer XXXXXXXXXX\r\n"
    )
);
$context = stream_context_create($request_options);

$url = 'https://api.shop-pro.jp/v1/customers/' . $_POST['id'] . '.json';
$response_body = file_get_contents($url, false, $context);
$response_json = json_decode($response_body, true);

$url2 = 'https://api.shop-pro.jp/v1/products/' . $_POST['pid'] . '.json';
$response_body2 = file_get_contents($url2, false, $context);
$response_json2 = json_decode($response_body2, true);

mb_language("Japanese");
mb_internal_encoding("UTF-8");

$to = 'info@example.jp';
$subject = $response_json['customer']['name'] . ' 様から再入荷登録';
$message = $_POST['pid'] . ', '. $response_json2['product']['name'] . ', ' . $response_json['customer']['mail'];
$headers = 'From: info@example.jp' . "\r\n";

mb_send_mail($to, $subject, $message, $headers);
header(sprintf("Location: http://example.jp/?pid=%s", urlencode($_POST['pid'])));
exit();


2. 妙な仕様


カラーミーAPI実践編2 ポイント表示」をベースに、妙な仕様にしています(楽&長くならない範囲にするため)。省いたところは、ご自身で調べてください。

クリックしたら即メールで、パラメータのバリデーション、ログインのチェック、「登録しました」の表示や、お客様に登録完了メールを送らないのも、作りとしてはかなり省略しています。
コピペしたらすぐに使えるような仕様にはなっていません。改造・自習用にどうぞ。
ブログの都合上、改行不要なところに改行が入っていますので、注意してください。

仕様は、クリックすると、商品IDと会員IDをPHPに送って、カラーミーショップAPIで必要項目をとってきます。
上例では、商品ID、商品名、会員登録しているメールアドレスを、お店にメール送信するようになっています(ログインしていないとメールアドレスは空です)。
$toがお店宛。
お店メールで受けて、お店でメモするなり管理します。

商品詳細ページから必要な情報をすべて送れるなら、カラーミーショップAPIは不要(本当に必要な情報は、商品名とメールアドレスくらい)。


ログイン限定にするなら、会員の名前も送って、会員IDと名前をカラーミーショップAPIでチェックすれば、いたずら避けになるかと思います。


ログイン不要にするなら、メール登録の入力フォームを開くときにサーバーからトークンを送ってもらうかたちにします。検索するとトークン生成の方法が見つかります。
クリックするとPHPを呼び出し、PHPで入力フォームを作って、そこでメールアドレスを入力してもらうようにします。
他人のメールアドレスを勝手に登録されるようないたずらは除外できません。


上例には例外処理を書いていません。
例えば、送られてきた会員ID・商品IDが該当しない場合(これはありえます)。カラーミーショップAPIでエラーになるので、その場合の処理が必要です。


3. おわりに


データベースに登録~在庫チェック~メール送信までの流れも検討しましたので、まとまった時間のあるときにでも、試してみようかと思います。 

とはいえ、自分自身で調べられる方でないと、実際に運用していくことは難しいかもと思います。

再入荷お知らせメールの話2へ続く。

[参考]
IPA - 安全なウェブサイトの作り方
セキュリティ上の問題となる箇所と対応について記載されています。ウェブアプリケーション構築において重要な話題ですので、ご一読を。