もしもドロップシッピングをECCubeを使って管理したい(2)

続きです。

なぜか、商品CSVアップロードからアップロードできませんでした。新しいウィンドウが開き、しばらくすると商品CSVアップロード画面が再度表示されてしまう。該当するソース(/data/class/pages/admin/products/LC_Page_Admin_Products_UploadCSV.php)を眺めていても、特に・・・と思っていたら、ピーンと来ました。post_max_size と upload_max_filesizeがアップロードするファイルに対して(85M!!)小さすぎました。

ということで、php.iniの値を変更するとともに、/html/.htaccessphp_value upload_max_filesizeを100Mに変更し、再度トライ。結果、「CSVファイルではありません」とのこと。いずれにしても85Mのアップロードは、現実的ではないので、直接SQLをたたくようにしようと方向転換します。

ちなみに、同じところで詰まっていた人の情報で、下記を修正する必要があるようです。SQLを直接たたくなら、必要ないかも。

/data/class/pages/admin/products/LC_Page_Admin_Products_UploadCSV.php

の229行目付近のにCSVの項目が記述されていますが
ここで必須項目(存在の有無)を確認する"EXIST_CHECK" "FILE_EXISTS"を削除するとできました。

$this->objFormParam->addParam("メイン画像", "main_image", LTEXT_LEN, "KVa", array("EXIST_CHECK","FILE_EXISTS","SPTAB_CHECK","MAX_LENGTH_CHECK"));

↓

$this->objFormParam->addParam("メイン画像", "main_image", LTEXT_LEN, "KVa", array("SPTAB_CHECK","MAX_LENGTH_CHECK"));

もしもドロップシッピングをECCubeを使って管理したい(1)

このご時世、ちょっとでもお金を稼ごうと思いまして、もしもドロップシッピングをECCubeを利用して管理しようと考えました。
今回は、商品データベースにデータを入れます。

-- ダウンロードしたデータをインポートするテーブル
CREATE TABLE articles
(
  goods_id integer NOT NULL, -- 商品ID
  goods_name text,
  category_name text,
  tag_name text,
  maker_name text,
  goods_number text,
  wholesale_price integer,
  low_price integer,
  selling_price integer,
  recommended_price integer,
  catch_copy text,
  shop_explain text,
  goods_explain text,
  spec text,
  image_code text,
  image_num integer,
  same_parcel text,
  settlement_method text,
  last_update timestamp with time zone,
  CONSTRAINT articles_pkey PRIMARY KEY (goods_id)
)

-- ECCube対応のCSV出力を行うために利用するテーブル
CREATE TABLE wrk_articles
(
  c001 text NOT NULL,
  c002 text,
  c003 text,
  c004 text,
  c005 text,
  c006 text,
  c007 text,
  c008 text,
  c009 text,
  c010 text,
  c011 text,
  c012 text,
  c013 text,
  c014 text,
  c015 text,
  c016 text,
  c017 text,
  c018 text,
  c019 text,
  c020 text,
  c021 text,
  c022 text,
  c023 text,
  c024 text,
  c025 text,
  c026 text,
  c027 text,
  c028 text,
  c029 text,
  c030 text,
  c031 text,
  c032 text,
  c033 text,
  c034 text,
  c035 text,
  c036 text,
  c037 text,
  c038 text,
  c039 text,
  c040 text,
  c041 text,
  c042 text,
  c043 text,
  c044 text,
  c045 text,
  c046 text,
  c047 text,
  c048 text,
  c049 text,
  c050 text,
  c051 text,
  c052 text,
  c053 text,
  c054 text,
  c055 text,
  c056 text,
  c057 text,
  c058 text,
  CONSTRAINT wrk_articles_pkey PRIMARY KEY (c001)
)

手順

1.もしもドロップシッピングよりデータ(articles.csv)をダウンロードする(https://www.moshimo.com/shop/download#specific-url-article-image)
2.articles.csvをインポート

set client_encoding to ‘SJIS′;
COPY articles FROM E'C:\\tmp\\articles.txt' with CSV;

3.ワークテーブルにデータを挿入する

INSERT INTO wrk_articles(
            c001, c002, c003, c004, c005, c006, c007, c008, c009, c010, c011, 
            c012, c013, c014, c015, c016, c017, c018, c019, c020, c021, c022, 
            c023, c024, c025, c026, c027, c028, c029, c030, c031, c032, c033, 
            c034, c035, c036, c037, c038, c039, c040, c041, c042, c043, c044, 
            c045, c046, c047, c048, c049, c050, c051, c052, c053, c054, c055, 
            c056, c057, c058)
 
SELECT 

goods_id as 	c001	, -- 	商品ID	goods_id 
goods_number as c002	, -- 	商品規格ID	goods_number
null as 	c003	, -- 	規格名1	
null as 	c004	, -- 	規格名2	
goods_name as 	c005	, -- 	商品名(※ 必須)	goods_name 
null as 	c006	, -- 	公開フラグ(1:公開 2:非公開)(※ 必須)	
null as 	c007	, -- 	商品ステータス(※ 必須)	
null as 	c008	, -- 	商品コード	
recommended_price as 	c009	, -- 	通常価格	recommended_price
selling_price as 	c010	, -- 	販売価格(※ 必須)	selling_price
null as 	c011	, -- 	在庫数	
null as 	c012	, -- 	送料	
null as 	c013	, -- 	ポイント付与率(※ 必須)	
null as 	c014	, -- 	購入制限	
maker_name as 	c015	, -- 	メーカーURL	maker_name
null as 	c016	, -- 	検索ワード	tag_name
null as 	c017	, -- 	備考欄(SHOP専用)	shop_explain,wholesale_price,low_price,image_num
catch_copy as 	c018	, -- 	一覧-メインコメント(※ 必須)	catch_copy
'http://image.moshimo.com/item_image/'||image_code||'/1/m.jpg'
		as 	c019	, -- 	一覧-メイン画像(※ 必須)	http://image.moshimo.com/item_image/image_code/1/m.jpg
goods_explain as 	c020	, -- 	メインコメント(※ 必須)	goods_explain
'http://image.moshimo.com/item_image/'||image_code||'/1/m.jpg'
		as 	c021	, -- 	メイン画像(※ 必須)	http://image.moshimo.com/item_image/image_code/1/m.jpg
'http://image.moshimo.com/item_image/'||image_code||'/1/l.jpg'
	as 	c022	, -- 	メイン拡大画像	http://image.moshimo.com/item_image/image_code/1/l.jpg
null as 	c023	, -- 	カラー比較画像	
null as 	c024	, -- 	商品詳細ファイル	
'スペック' as 	c025	, -- 	詳細-サブタイトル(1)	スペック
spec as 	c026	, -- 	詳細-サブコメント(1)	spec
null as 	c027	, -- 	詳細-サブ画像(1)	
null as 	c028	, -- 	詳細-サブ拡大画像(1)	
'同梱可否' as 	c029	, -- 	詳細-サブタイトル(2)	同梱可否
'same_parcel' as 	c030	, -- 	詳細-サブコメント(2)	same_parcel
null as 	c031	, -- 	詳細-サブ画像(2)	
null as 	c032	, -- 	詳細-サブ拡大画像(2)	
'決済方法' as 	c033	, -- 	詳細-サブタイトル(3)	"決済方法	"
settlement_method as 	c034	, -- 	詳細-サブコメント(3)	settlement_method
null as 	c035	, -- 	詳細-サブ画像(3)	
null as 	c036	, -- 	詳細-サブ拡大画像(3)	
'最終更新日時' as 	c037	, -- 	詳細-サブタイトル(4)	最終更新日時
last_update as 	c038	, -- 	詳細-サブコメント(4)	last_update
null as 	c039	, -- 	詳細-サブ画像(4)	
null as 	c040	, -- 	詳細-サブ拡大画像(4)	
null as 	c041	, -- 	詳細-サブタイトル(5)	
null as 	c042	, -- 	詳細-サブコメント(5)	
null as 	c043	, -- 	詳細-サブ画像(5)	
null as 	c044	, -- 	詳細-サブ拡大画像(5)	
null as 	c045	, -- 	発送日目安	
null as 	c046	, -- 	おすすめ商品(1)	
null as 	c047	, -- 	詳細-サブコメント(1)	
null as 	c048	, -- 	おすすめ商品(2)	
null as 	c049	, -- 	詳細-サブコメント(2)	
null as 	c050	, -- 	おすすめ商品(3)	
null as 	c051	, -- 	詳細-サブコメント(3)	
null as 	c052	, -- 	おすすめ商品(4)	
null as 	c053	, -- 	詳細-サブコメント(4)	
null as 	c054	, -- 	おすすめ商品(5)	
null as 	c055	, -- 	詳細-サブコメント(5)	
null as 	c056	, -- 	おすすめ商品(6)	
null as 	c057	, -- 	詳細-サブコメント(6)	
category_name as 	c058 -- 	商品カテゴリ(※ 必須)	category_name

FROM 
  public.articles;

4.CSVファイルとしてエクスポートする

COPY wrk_articles TO E'c:\\tmp\\import.txt' DELIMITERS ',';

なお、wrk_articlesテーブルで確認するSQLは下記通り。

SELECT c001, c005, c006, c007, c010, 
       c013, c018, c019, c020, c021, c058
  FROM wrk_articles
where
	c005 = null
or
	c006 = null
or
	c007 = null
or
	c010 = null
or
	c013 = null
or
	c018 = null
or
	c019 = null
or
	c020 = null
or
	c021 = null
or
	c058 = null


エクスポートデータしたデータを商品インポートよりインポートにて完了・・・と思いきや、なぜかうまくいかない・・・。疲れたから、今日はこれにて終了。

PostgreSQLのCSVからのインポート処理についてのまとめ

-- 「\」1つではエスケープされるのでだめ
COPY tablename FROM 'C:\test\testdata.csv' WITH CSV;
-- WARNING:  nonstandard use of escape in a string literal
-- ERROR:  could not open file "C:testtestdata.csv" for reading: No such file or directory

-- 「\」2つでもなぜかエラーが出てだめ、ではなくて、警告が出るが実行はOK
COPY tablename FROM 'C:\\test\\testdata.csv' WITH CSV;
-- WARNING:  nonstandard use of \\ in a string literal
-- HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.

-- ヒントにあるように「E」をつければ警告なしで実行OK
COPY tablename FROM E'C:\\test\\testdata.csv' WITH CSV;

-- パスに日本語が入っているとだめ(マルチバイトへの何らかの対応が必要?)
COPY tablename FROM 'C:/Documents and Settings/User/デスクトップ/testdata.csv' WITH CSV;
-- ERROR:  could not open file "C:/Documents and Settings/User/デスクトップ/testdata.csv" for reading: No such file or directory

-- 文字コードがファイルとDBで異なっていてもエラーとなります。
-- ERROR: invalid byte sequence for encoding "UTF8"

--EXCELで作成したCSVだとShift-JISになってしまうので、エディタで変換して保存し直すか、下記にて対応
SET client_encoding TO 'SJIS';
COPY tablename FROM 'C:/test/testdata.csv' WITH CSV;

デミリタを変えれば、ダブルコーテーション問題は解決。
・・・と思っていたら、
ERROR: extra data after last expected column
と、エラーメッセージが出力される。

結論。

COPY test FROM '/home/postgres/test.csv' WITH CSV;

で解決。

インポートは、

set client_encoding to ‘SJIS′;
COPY articles FROM E'C:\\tmp\\articles.txt' with CSV;

でOK。

PHPと設定ファイルについて

PHPで定数を設定するファイルを何にしようか考え中。

  1. 通常のPHPファイルに配列やdefineで宣言
  2. iniファイル
  3. XMLファイル
  4. YAMLファイル

今は、通常のPHPファイルに宣言していて、特に不満はないのだけれど、外部ファイル化することで、ソースに手を入れなくても設定が変更できるのは捨てがたい。

iniファイルは、PHPに読み込み、書き込みの関数が用意されているので、簡単に使えるのだが、フォーマットの仕様上、配列のような使い方や、定数のネスト表現ができない。ちょっと不満が残る。

YAMLファイルはフォーマットがわかりやすいイメージがあるのだけれど、ライブラリを別途用意しないと利用できない(もちろん自分で作ることも可能だけれども)ので、バージョンアップなどを考え、二の足を踏んでいる。

となると、PHP5からバンドルされているsimplexmlを利用して、XML形式で作成するのがよさそうなのだが、XMLファイルって何気に面倒くさい。

今だ、悩み中。

お勉強

MySQLPostgreSQLの型の違い

数値データ型について
PostgreSQL
 smallint、int、bigint、decimal、numeric
MySQL
 tinyint、smallint、mediumint、int、bigint、decimal、numeric

smallint,int,bigint,decimal,numericは共用できそうだ。ただし、桁数が違う可能性があるので注意が必要。
(http://www.thinkit.co.jp/free/article/0703/13/1/)

文字列型
PostgreSQL
 char、varchar、text
MySQL
 char、varchar、text、mediumtext、longtext

char、varchar、textは共用できる。
MySQLは、char型は最大255文字の制限が明確になっており、それ以上はtext型を使う。一方、PostgreSQLは1,000万文字ほどの文字列をchar型に格納できる。ここはMySQLに準拠したほうがよさそうだ。
PostgreSQLのtext型は無制限だが、MySQLのtext型は65535文字までしか格納できない。text型についても、MySQLに合わせる。

日付型
PostgreSQL
date、time、timestamp、interval
MySQL
date、time、timestamp、datetime、year

date、time、timestampは共用可能。日付型は自動更新が可能だが、DBの種類とバージョンによって指定方法が異なる。
PostgreSQLの場合は、デフォルト制約で「current_timestamp」を定義しておく必要がある。また、自動更新は新規挿入時のみ(insert)で、更新時(update)には更新されない。
一方、MySQLのtimestamp型は、INSERTやUPDATEによって現在の日付時刻を自動で更新する。

MySQL(Ver4.x)では、システム変数は指定できず、定数のみ指定できない。(http://oshiete1.goo.ne.jp/qa1176802.html)

ただし、TIMESTAMP型にすれば、一つのテーブルにつき一つだけ値を自動更新可能。(​http://www.mysql.gr.jp/Manual/mysql-4.00.12/manual.ja_Reference.htm...​)

以上を踏まえ、日付更新処理はDB側の自動更新を使わずアプリ側で対応したほうが無難と言える。

また、格納する日付書式が間違っている場合、PostgreSQLはエラーを返すがMySQLは「0000-00-00」といった値(といった値って何だろう?)が格納されるようだ。

これは、MySQLが「SQL Modes」と呼ばれるMySQLサーバの設定状態があるため。PostgreSQLでも同様に設定可能なので、DBのチェックに頼らず、アプリ側で日付書式チェックを行う。また、日付型を使わず、文字列型で対応することも検討。
# Selectするときにキャストするのが面倒なんだよなぁ

SQL

おおむね、PostgreSQLに合わせておけば大丈夫。というか、標準の(SQL99だっけ?)に準拠すれば、大体の場合は大丈夫だと思われる。

文字コード
PostgreSQL 8.1.8
 EUC-JP
 UTF-8
MySQL 5.0.22
 EUC-JP
 Shift-JIS
 UTF-8
 UCS-2
 cp932

EUC-JPかUTF-8に合わせる。

ビュー、ストアドプロシージャ、トリガー

ビューは、閲覧目的で利用するのみとしたい。更新対応まで考えると挙動を合わせるのが複雑になる可能性があるから。
ストアドプロシージャ、トリガーとも、基本的には利用しない方向にしたい。利用する場合には、個別対応とすること。

PostgreSQLメタデータを取得するためのSQL

select * from pg_tables 
where 
	not tablename like 'pg%' 
and
	schemaname like 'public'
order by tablename
;

select 
	attname, atttypid, attlen
from 
	pg_attribute
where 
	attnum > 0
and 
	attrelid = (select relfilenode from pg_class where relname = 'tbl_news')
order by 
	attnum
;

select * from pg_class where relname = 'tbl_news'


SELECT
    sut.relname,
    pg_attribute.attnum AS NUM,
    pg_attribute.attname AS COL_NAME,
    typ.typname AS COL_TYPE,
    CASE typ.typname
        WHEN 'varchar'   THEN pg_attribute.atttypmod-4
        WHEN 'bpchar'    THEN pg_attribute.atttypmod-4
        WHEN 'numeric'   THEN pg_attribute.atttypmod/65536
        WHEN 'date'      THEN pg_attribute.attlen
        WHEN 'timestamp' THEN pg_attribute.attlen
    END AS COL_LENGTH,
    pg_attribute.attnotnull
FROM
    pg_stat_user_tables sut inner join pg_attribute  on pg_attribute.attrelid = sut.relid
    inner join  pg_type typ on pg_attribute.atttypid = typ.oid
WHERE
    pg_attribute.attnum > 0

ORDER BY
    sut.relid , 
    pg_attribute.attnum
ついでにPHPデータベース接続クラスのPDOマニュアル

http://php.net/manual/ja/book.pdo.php