伊藤清徳の垂直落下式ムーンサルトプレス

PerlとかPHPとかMySQLとか...がんばっても8割だ。

Author: admin (page 1 of 28)

焼失してしまった沖縄首里城へ祈りをささげにいってきた。

まず最初に、沖縄に関わる全ての人々に衝撃と落胆、大きな喪失感をあたえた、首里城火災に際して、時間はかかるのかもしれませんが、沖縄の人々の叡智で、再建計画が進み、そして、その計画が実ることを心から祈っております。

つぎに、沖縄に来はじめて20年近く経ち、ここ数年はほぼ毎月来ている僕とは言えど、首里城焼失に関して、単なる雑記ブログであるこのブログに記事を書いて良いものか悩んではいたのですが、たとえば30年後の2049年に首里城が、再び沖縄の人々の象徴となり、全日本全世界の人々の共有文化財になったとき、一つの記録として意味のあるものなるのかもしれないという思いでこの記事を書きます。様々な意見や思いがあるとは思うのですが、僕個人の日記ということでご容赦いただけると幸いです。

2019年10月31日未明それは起きた

2019年10月31日。朝起きて、スマホでYahoo!ニュースを見て、それを知る。「首里城焼失」。この文字の並びの意味を理解するのに2分3分くらいはかかった。ありうることなのか?僕が、2001年8月にはじめて沖縄に来たときから、そこに当たり前にあるものがなくなるということがあるのか、理解ができなかった。そんなことがあるのか?理解したあとも、そう思った。地元沖縄の沖縄タイムスや琉球新報を見ると、ショックで登校できない小学生がいるという記事を見て、事の大きさを理解した。実感した。と、火災から数日経って、この記事を書いている今、振り返ると、そう思う。

偶然にも、火災から3日後の2019年11月3日に沖縄那覇にいく予定であったため、到着は夜ではあるものの、まっさきに首里城へ向かうことを決めた。

そこにあるのは風景だった

11月3日18:30 那覇空港に着。
僕たちが那覇で利用するアパートは、那覇空港から車で25分程度、首里城へは車で7分程度のところにある。すぐに行ける距離であるため、まっさきに向かったわけだ。
11月3日は文化の日。土日が絡めば、3連休以上になる。今年2019年も3連休。「これまでの首里城」では、ライトアップが行われるため、19:00くらいではまだ人がいるのだが、僕が首里城公園の龍潭についた19:00には人はだれもなかった。

覚悟はしていた。が、恐ろしく残酷な風景がそこにはあった。あるはずのものがない。
夜の首里城は、漆の効果により、とても美しく映えていた。再建計画が進む中、瓦の色などは、戦前の焼失の前とはちがっていたことが古い資料から判明しているそうだが、それを差し置いてもきれいであった。正直なところ、首里城が健在の頃は、昼の姿より夜の姿のが好きであった
しかし、それがないのだ。


撮影場所が違うけれども、これが2010年夏の首里城の夜がこの雰囲気だ。全く別物になっているのがこれだけでもわかる。

10月31日の未明。あれだけのものが焼失してしまうほどの火災があったのだ。小さい小学生にとって、物々しい雰囲気が街を包み、登校ができなくなるのも納得できたのは、やはりこの場に立ってからだ。

この日は仕事がまだ残っていたので、首里城を後にし、仕事に向かう。

明るくなって見えたものは廃墟だった

明くる日の11月4日。再度首里城公園を訪れる。

昨晩真っ暗であったそこには明らかに焼け焦げた建物がある。ご注意いただきたいのは、この焼け焦げた建物は北殿という建物で、観光案内などで見る立派な建物正殿ではない。このアングルから見えるはずの正殿は、見ることができない。マスコミ報道で既報の通り、正殿は完全に焼け落ちた。見る影もないというのが、ようやく理解できた感じがする。

龍潭から首里城正殿方面にあがっていく。心配して見に来る沖縄県民、もともと旅程にはいっていたので見に来る観光客、そして、マスコミ。以前訪れたときとは明らかに違う龍潭から首里城公園正殿方面への道。首里城公園の休園をお知らせする張り紙があちこちにある。何人かのうちなーんちゅに声をかけた。不思議と悲壮感はない。うちなーの気質なのかもしれないが、もう一度再建するし、できると信じている人が多いように感じた


守礼門のほうまで、放水ホースが引かれたままだった。報道によると、火災翌日になっても煙はあがったままだっただということで、火災自体が大きなものであったことを感じさせる。


いつもだったら琉装記念写真を撮ることができる守礼門も、休園なので、スタッフも不在。客足もまばらである。

首里城公園メインエリアは歓会門まで


首里城公園メインエリアの一般立ち入りは歓会門までとなり、それ以外の大部分は規制線がはられていた。たくさんのひとが、どうすることもできないままに、言葉なく正殿方向を見ていた。


黒いTシャツのお兄さん。あなたのすぐ左手にある建物。園比屋武御嶽石門(そのひゃんうたきいしもん)が、首里城公園においては建造物として唯一の世界遺産なのですよ。と思いつつも、シンボルである正殿を失った首里城公園は、報道のヘリが放つ喧騒だけが鳴り響いていた。


ちょうどこの日午後に県関係者、国会議員などが火災現場視察をするということで、県警の偉い人だと思われる人々が、正殿方面にたくさん上がっていっていた。

首里のすべてが失われたわけではない


首里城公園のすぐとなりには、こんなきれいな石畳道がある。この付近には首里が聖地である所以のひとつとなる湧き水があったり、古くからの家屋があったり。紅型のお店もある。観光に行くに値する町並みだ。とくに、石畳茶屋「真珠(まだま)」は、僕が沖縄にいきはじめたころからあるお店。那覇市街を一望しながらゆったりとお茶を飲むのは最高の時間だ。


首里城公園の人工池龍潭の横には、不思議な鳥「バリケン」たちが、みんなを待っている。

前述の通り、首里城公園唯一の建造物としての世界遺産「園比屋武御嶽石門」は健在だし、首里城の遺構そのものが世界遺産であるため首里城の価値も失われていない。とにかく間違えてはいけないのは首里の価値は失われていない。いまだから行こうとかそんなきれい事を言う気はさらさらないが、行く意味はまだまだある。観光で沖縄にはじめて行く人々にとっては、行ってほしい場所のひとつであることには変わりがないことを確認した。


警察官たちもマスコミ対応や、入場規制への対応で人が増員されていた。

うちなーんちゅの人たち

何人かのうちなーんちゅに話を聞いた。みんな揃っていうのは「自分が生きているうちにもう一度首里城の復元は見られるのか」。
首里城の復元においては障壁がかなり高いことがわかってきている。

  • 首里城に使われた琉球瓦は、首里城の前回の復元の際には、すでに1社のみしか持たない技術で、その匠もすでに他界していらっしゃり、技術自体がすでに失われている。
  • 前回の修復時は、台湾の木材を利用して、修復が行われているが、現在台湾は木材を輸出することができなくなっており、木材が大量に足らないのではないか?
  • 前回の修復時は、工具なども琉球王朝時代に利用された工具を使う試みが行われ、日本中から集められた匠たちは、個々人の研究において使い方を探り建築された。その技術自体の復元のハードルが高い

など。さすがのうちなー。こういった情報は細かくご存じの方が多い。過去にはなかった技術で復元を早められることを祈るばかりだ。
また、さまざまな意見の中には、復元にあたり漆は塗らなくてもいいのではないか? 復元後はライトアップは要らないのではないか?という意見もあった。こういった意見もかんたんには否定できない。うちなーのシンボルとしてのあり方としては、観光資源よりそちらを優先したいという意見も間違っていないだろう。

どういった形にせよ、失われて初めて感じることなのかもしれないが、とにかく上述の通り、沖縄県民の叡智をもって、復元計画が進むのを待つばかりである。

支援は広がる

沖縄県がクラウドファンディングにて支援を受け付けている。11月4日の滞在時、沖縄県内のラジオを聞いていると、支援が2億をこえ、もうすぐ3億だというニュースを聞いた。
知り合いの沖縄古典芸能をやっていらっしゃる仲嶺良盛さんはチャリティーコンサートを開いた。
沖縄を離れた場所においては、懇意にしている愛知県岡崎市の「いちゃりばちょーでー」では、店主手作りのグッズを通じて支援を募っている。
とにかく大小さまざまな支援がひろがっている。
僕は琉球エアーコミューターを通じて、手持ちのJALマイレージを全額寄付手続きを行った。

おそらく、この首里城ショックは、一種の「旬」みたいなもので、少しの時間をすぎれば、やや下火になってしまうことは致し方ない。2019年は様々な自然災害が日本各地を襲い人命に関わる災害もたくさん起きた中で、同じレベルで首里城の焼失を捉えられるかというと、やはりそれにも無理があるのは否めない。

たとえば、もし「ちょっと毎日に疲れたな」とおもったのだったら、ちょっと沖縄へ行ってみる。というのでも僕は十分な支援になると思っている。(LCCで安くいけるよ!)熱い支援でなくてもよいので、世界遺産である首里城公園の復元に少しだけでも、多くの人の関心が寄せられればと僕は思う。

30年後(になるかわからないけれども)の復元時に、この記事が、なにかの役に立っていることを願って。
現場からは以上です。

ベトナムホーチミン ブイビエン通り に泊まってきた

どうもきよっちこと伊藤でございます。

2019年9月に1週間弱ほど、ベトナムホーチミンに行ってきました。1年ぶり2回目の訪問。仕事での訪問ではありますが、楽しめることもたくさんあったので、報告がてら書いてみようとおもいます。

旅程順に書かずに、立ち寄った場所ごとにまとめて書きますので、参考になさっていただけると幸いです。

この記事では、ベンタイン市場などの有名な観光地のお話は省きます。

空路について

中部国際空港発着 タンソンニャット国際空港行き ベトナム航空の直行便にて行きました。
行きは日本時間10:00ごろ出発 現地時間14:30ごろ着
帰りは現地時間00:05出発 日本時間07:30ごろ着(つまり深夜便)
です。往復で燃油サーチャージなどを含んで、おおよそ往復で5万強程度(エコノミークラス)です。2019年9月現在は中部セントレアとホーチミンを結ぶ便は、エアバス321機で運行されています。

A321は、3列×3列のいわゆる「ナローボディ機」でして、けっこう狭いのが難点ではあります。ベトナムの国民性なのか、やたらとエアコンを寒くするのが普通らしく、席にはブランケットとクッションが昼便であろうとも置かれています。女性など寒さに弱い方はあらかじめ厚めの服装にて搭乗なされることをおすすめします。

今回はエアトリにてチケットをとりました。webチェックインは出発24時間前から行うことができます。逆に言えばそれまで席の指定はできません。ナローボディ機であれば広さがほしいので、非常口席か、最後尾席が良いかと思いますので、そこを確実にとるには24時間前のwebチェックインが必要です。
※非常口席は英語での最低限コミュニケーションを必要とするので、英語に自信がない方はNGです

機内食は比較的おいしいほうにはいる機内食だとおもいます。味のバランスもよいですし、フルーツなども美味しいですね。ただし帰りの便は、午前3:30ごろから食事となります。眠りたい人はあらかじめアテンダントに食事はいらないとつたえておくとよいです。

タンソンニャット国際空港について

タンソンニャット国際空港は、軍民共用空港となっており、イミグレーションなどは軍が管轄する空港です。入国審査も軍人が行いますが、審査基準は一定ではなく、入る際には人によって求められるものが違います。あらかじめ手元に用意しておいたほうがよいものとして

  • Eチケット
  • 帰り便の予約番号と時間わかるもの(予約控え)
  • ネット環境

は用意した上で、入国審査を受けるのが良いです。人によっていずれかを求められます。印刷もEチケットも両方持っていないとどちらを求められるかわからないため入国に難儀することがあります。

ベトナムを出国して帰る際も、手荷物検査などは軍の管轄です。バゲッジドロップにて荷物を預けると、空港のモニタにいま自分の荷物がどうなっているのかが表示されていますので、アラートが出ていないかを確認した上で、制限区域に進む必要があります。成田の第三ターミナルと同じような仕組みですね。ですので、この点においては懸念があるわけなので、空港にはちょっと早めにいって荷物を預けておくのが良いです。
手荷物検査は、靴をぬいで、金属探知機をくぐらなければなりません。脱ぎづらい靴はおすすめしません。

また帰りの検査は、軍の掌握で進められているので、かなり厳格です。僕はAppleMacBookPro2016の15インチをもっているのですが、発火危険性がある機種ということで、別室についれていかれ、いつどのような形でどこから買ったのかを細かく聞かれたうえに、PCのシリアルナンバーをテロ疑いありリストに記載されたうえで、厳密な身体検査を受けました。外国でこのような扱いを受けることは、とても不安になることです。あらかじめ、自分が持っているPCが国外でどのような扱いを受けているのかを知った上で、ベトナムには向かったようが良いです。
ベトナムに限らずですが、アジア各国の入出国審査には袖の下を求められることも多々あります。ルールブックは向こうにあります。最悪MacBookを渡して帰る覚悟が要ります。(ので、データは外に出すべし)

タンソンニャット国際空港は、ホーチミン市中心部まで、タクシーでおよそ30分程度。値段にしておよそ130,000ドン、日本円で600円くらいあれば、中心部にいくことができます。タクシーはよほどベトナムに慣れていない限り、絶対にVINASUN(ヴィナサン)か MAI LINH(マイリン)以外は乗ってはいけません。これ以外のタクシー会社は、基本的にぼったくりです。ベトナムは非常に治安のよい国ですが、ひったくりとぼったくりはめちゃくちゃに多いです。

ホーチミン市街地について


ホーチミンシティは、とても広い市で、人口は850万人弱で、東京都全体とおよそ同じくらいの広さがある市です。ワンルームマンションの家賃が東京23区内と変わらない富裕層居住地域から、スラム街まである、ひとつの小さな国を凝縮したような、多様な姿を見せる街です。日本人には考えることができないほどのバイクの数が走っており、日本人には理解ができない交通ルールで無数のバイクが道を埋め尽くしており、それだけで、圧倒されてしまいます。はっきり言うと日本人は最初は道を横断することができません
セブンイレブンやファミリーマートといった馴染みのある店がたくさんあり、物価は安いですし、宿泊する上で、必需品に困ることはありません。しかしペットボトルのお茶の最安価格が20,000ドンという慣れない単位には、非常に悩まされます。2万ドンはおよそ100円弱程度。つまり200で割った数字が、日本円近似値になります。まじでデノミしてくれとおもいます。

日本人韓国人とすれ違うことが多く、また欧米人もよく見かけます。国際都市ですね。コミュニケーションは、日本人が立ち寄るような場所では、英語でほとんどいけますが、アジア英語なの聞き取れないことも多々あります。スターバックスコーヒーもあれば、イオンモールもあるし、丸亀製麺もあります。から本当に困りません。

しかし、本当に街が汚いです。あまり清掃をするという倫理観がない国のようで、自分の家や店の前にゴミを放り投げるということに対しては、なんとも思わないようです。ホーチミンはとても暖かい地方で、夏はいかないほうがいいくらい暑いわけですが、とはいえ、裸足にサンダルのような格好は、とても足がよごれて不潔感はありますので、おすすめしません

治安は外国としてはトップレベルに治安がよく。よほどスラムのようなところに行かない限りは、夜女性が歩いていても問題がないレベルです。しかし、前述のとおり、ひったくりとぼったくりはたくさんありますので、例えばお札がいっぱいはいった財布をうかつに出すなどはNGです。

今回の宿泊場所ブイビエン通り


ホーチミンシティナンバーワンの繁華街です。毎晩 隅田川花火大会とディズニーランドのパレードが同時にやってきたような 人出と大騒ぎとなります。この中にあるホテルを使いました。
大騒ぎはどれくらいの大騒ぎかと言うと、この通りのクラブやディスコの類はすべて、アリーナコンサート級の音量が出せるスピーカーを、道に向けて音出しし、食事ができる屋台は道に勝手にステージ組をしてカラオケ大会を行い、そこに来る客が大声で歌えや飲めやです。各店のスピーカーはすべてしっかりウーファーが効いています。ホテルの部屋が通りに面した側の部屋だとほぼ確実に眠れないでしょう。
ネットで、この通りのことを調べると、大変に治安が悪いということを書いてありますが、ある一側面では正しいですが、必ずしも治安が悪いということはないです。この通りに5日いたわけですが、争い事や強盗のような「凶悪」なタイプの犯罪には出会っていませんし、ベトナムに詳しい友人も、そういったことは聞いたことがないと言っていました。しかし、ひったくり騒ぎや寸借詐欺のようなことは目撃しています。こそドロ的なものですね。あとは、笑気ガス遊び(日本でいえばシンナーで遊ぶみたいな感じですかね?)やマリファナ遊びをしている人は見かけます。日本人の感覚で言えば、ここは確かに治安が悪いですが、世界の感覚でいうと治安は悪くない(いいとは言っていない)という感じですね。
なお、友人からの注意で、この通りには、マッサージ屋が多々あります。かわいい女の子が客引きをしてきます。ほいほいついていくと途中でスペシャルマッサージ100ドルとか言ってきて、これはもしかしてムフフなやつかと思って払うと、力が強くなるだけのスペシャルだそうです。基本的にはベトナムでお金を要求してくるものは、すべてぼったくりだとおもって間違いないです。

3つ星ホテル


今回のホテルは3つ星ホテルにとまりました。海外の3つ星ホテルは、一般的には「スタンダード」と言われるクラス。つまりは「普通」ということなんですが、ベトナムにおける普通とはどんなものでしょうか?
まず、エントランスホールは、とても小さく、日本でいえば安いビジネスホテルと同様。ロビーはなく、ソファが1個ある程度です。
スタッフはスーツなどは着ておらずハーフパンツとTシャツです。スタッフとのコミュニケーションは英語で大丈夫ですが、「ベトナム訛り英語」で、僕たちの「日本語訛り英語」とイマイチ相性がわるいのか、聞きづらかったり伝わらなかったりします。昨年ホーチミンの4つ星ホテルに泊まりましたが、そんなことはありませんでした。端的にいうとスタッフの教育教養レベルが違うということですね。スタッフはみなやさしく親身です。しかし、ちょいちょいタクシーやツアーには興味がないのか?いいのがあるぞって勧めてきます。この類のはなしは、ぼったくりなので、のってはいけません
お部屋は、まさにスタンダードといえる設えでした。日本のビジネスホテルよりは広く、ちゃんとデスクもありますし、wifiも安定して使うことができます。トイレはTOTO製!シャワーの水圧も問題なしです。お湯もちゃんと出ました。しかし、どうも排水にトラップがないみたいで、悪臭がしました。ベッドの質は良くも悪くもありません。香港やシンガポールの3つ星は、設えがちょっといいけどせまいということが多いですが、ベトナムの3つ星ホテルは全体的には質素というのが感想です。
ベトナムのホテルを調べていると「窓あり・窓なし」とわざわざ書いてある事が多いです。明るさが欲しい人は窓ありとしましょう。
ホテルの屋上には、カフェがあり、そこで朝食を食べます。9月は雨期ですが、午前中はさわやかな天気で、眺めの良いカフェで食事を摂れるというのは、贅沢な時間の使い方だなと感じます。4つ星ホテルの場合は屋上はプールになっていたりしますが、ホテル屋上でなんだかの施設がついていることは、ベトナムでは多いようです。これもベトナムのひとつの愉しみとして、ホテルを予約する際に調べておくと良いでしょう。
宿泊代は、朝食がついて、1室1泊3600円くらいと格安。ベトナムの3つ星は良いとは言い切れませんが、体験の一つとしてはおもしろいものといえます。

ブイビエン通りでの食事

上述のような、大騒ぎ若者ストリートなので、ろくなものを食べられないのではないか?と感じてしまいますが、そんなことはありません。
アメリカンスタイルのピザ屋もありますし、有名な食堂もあります。バスキンロビンスやスターバックスコーヒーすらあります。
ブイビエン通りの中ではないですが、両端を出たすぐあたりには、高級料理店もあります(とは言っても、1人ディナーで3000円行かないくらいでは入れます)し、屋台もたくさん出ております。屋台はベトナム名物のバインミーがおすすめです。
要するにブイビエン通りは、なんか遊びたければここに来いというストリートなんです。ただし、場所代が乗っているのか、ホーチミンの物価と対比するとやや高いものが多いです。フォーが日本円で500円くらいしました。(他の場所では100円そこそこで食べられるところも多い)

番外編 金庫のカギをなくした

僕の旅行において最も高価な持ち物はMacBookProです。30万近くしますし、これがないと職業が成立しないので、ある意味命よりも大事なものです。常に保険もかけています。そんなものなので、海外での旅行では、MBPを金庫にいれることが多いです。今回泊まったホテルでも金庫に入れていたのですが、いまどき珍しい、番号式ではない金庫です。うぉ。。。となりましたが、そこにいれて、街に出ました。15分後、、、カギを無くした事に気づきます。。。やっちまった。。。
ホテルのフロントに言うと「まじか!はじめての経験だが、大丈夫。プロフェッショナルの誰かを呼ぶから、朝10時まで待ってろ」と言われました。「プロフェッショナルの誰か」ってなんだよ。。。ベトナム人の大丈夫は安心できない。カギをなくしたのが深夜。不安なまま夜が明け、10時くらいにやってきたのが、ボロボロのハーフパンツとTシャツで現れたにこやかな男性。なぜか荷物を何ももっていない。。。え!?とおもっていると、ポケットから針金2本(片方はテンションかけるためのものなので、平打麺みたいな針金)を出して20秒ほどで解錠!!!すげぇ!!!と、感動するもの、この男性いったい何のプロフェッショナルなんだ?この男性がすごいのか、この金庫のセキュリティが大丈夫なのか???とか、いろいろ頭が混乱しましたが、とにかく良かったです。海外でのイレギュラーは不安しか生みません。
ちなみに、日本に帰ったあと調べたところ、ホーチミンには、とてつもない量のバイクがあり、それに付随して、バイクのカギ紛失の件数もかなりあり、カギのプロフェッショナルはたくさんいるそうです。なので、カギをあけてくれた男性は本当にカギのプロなんでしょう。ということは、金庫のセキュリティが大丈夫ではない。。。

番外編 ホーチミンシティでのノマドワーク

僕はITのおしごとをしているので、インターネット回線がないと、まぁまぁ死に瀕します。ホーチミンでのネットは、レンタルwifiを借りてもっていったり、amazonでViettelという電話会社の4G回線格安SIMが買えるので それを持っていったりすればOKです。いずれの場合も回線速度は、下り10Mbpsから25Mbpsくらいは街なかでは出てくれますし、ちょっと中心部から離れても5Mbpsくらいは出てくれます。あまり日本国内と遜色ないですね。やはり日本国内と同様で、上りは速度が遅いです。
しかし、ホーチミンのお店のほとんどはフリーwifiを飛ばしてくれています。つまり、長居ができるカフェを見つければ、そこでお仕事はできます。
僕が愛用するのは、日本人町にあるCoffeeRepublic-the house小規模のベトナムコーヒーチェーンですが、コーヒー以外にも果物をつかったジュース(ぼくはライム・ジュースがお気に入り)やバインミーもあって、1日いられます。店員さんはみなさんわかりやすい英語をはなしてくださり、欧米人もノマドにつかっているカフェです。
ホーチミンにもスターバックスコーヒーはあります。スタバで仕事をしている人も多いのですが、スタバは1購入につき、1時間1端末しかwifiをつなぐことができず(POSと連結されて管理されています!!)、あまり安定はしていません。ので、ノマドワークにはおすすめできないですかねー。
なお、ホーチミンのノマドワークに使えるカフェは、価格は、日本のカフェと大差ありません。コーヒー1杯400円程度です。ので、安くお店にいられるかというと、そうとは言い切れません。

ホーチミンにはコワーキングスペースも多々あるので、調べていくとよいです。今回僕たちは、レオパレス21がやっているコワーキングに行ってまいりました。こちらもコミュニケーションは英語である必要があります。上述のカフェより、しっかりした英語でのコミュニケーションになるので、ベトナム人英語に耳が慣れた上で行くのがよさそうです。
ちなみにですが、ベトナムのコンビニには印刷をする機械は備えられていません。PCから紙での出力をする場合は、ホテルのロビーに頼むか、コワーキングでの印刷になります。なるべく紙に出す仕事を持っていかないようにするのが吉です。

番外編 「旅行者症候群」

ホーチミンで青唐辛子を食べたあとから、ずっとお腹の調子が悪く、帰国してからも1週間程度下痢がつづきました。最初は、強烈なカプサイシンで消化機能がおかしくなってしまったのだろうとおもっていましたが、さすがに1週間となると、何かが変だということで、病院に行きました。
近所のクリニックに行き、事情を話すを「あーはいはい。なるほど」という先生の反応。先生の診断はすぐに降りて「旅行者症候群」という病気でした。症候群なので「風邪」みたいな大枠な診断ですが、僕の症状の場合は次のとおりです。
現地の常在菌が体内に入った結果、自分常在菌より勝ってしまい、腸内で現地の常在菌が増殖。身体はこれまでになかったものなので、排出しようとして下痢を起こす。一回排出できたとしても、現地常在菌のほうが勝っている状態なので、体内でまた増殖し、身体は下痢として排出しようとする。というのを繰り返している症状です。
腸内菌を一旦殺してしまうという薬の処方をうけて、すぐになおりました。
現地の常在菌が悪性の菌というわけではなくて、僕の体内菌との相性の問題ということなんだそうで、海外にいくときは、ビオフェルミンなどで、体内の菌を強化・調整を予め行った上で、行くとよいそうです

体験は何にも勝る

日本人のパスポートの所有率は、全人口の25%程度しかないそうです。イメージよりよりかなり少ないです。先進国の中では下位です。都道府県別に見ると10%を切る県もあります。
日本は国内だけで完結ができるとても良い国です。日本のことしか知らなくて困ることは、必要の上では、ほとんどないと言えます。バインミーなんて日本でも食べられますし、なんだったら日本人がつくるバインミーのがおいしかったりします。しかし、そんな日本が海外からどう見られているのかは出てみないとわかりませんし、ベトナム実習生受入れ社会問題もその性質も外から見てみないとわからないでしょう。つまりは、もう一側面から見れば、世界で起きているほとんどのことを「対岸の火事」と捉えてしまえる国でもあります。
ブイビエン通では日本人は、まったくといっていいほど見ませんでした。中国人も韓国人も欧米人もたくさんいるのにです。おそらく、日本人の治安に対するレベル感が、他国の意識より高すぎるのでしょう。これは良いことなのかもしれません。他方で、ネットで調べた情報だけをもとに、判断し「行かないほうがいい」という判断をしているのでしたら、それは本当に良いことなのかは疑問符です。身近なひとの体験から判断しているのでしたら良いのですが。もし、この記事を読んでくださっている方は、ブイビエン通りで泊まれとはいいません。遊びに行ってみてください。
今回は、5日間になまってしまった体験頭脳を活性化できる良い旅だったと思います。

が、しばらく東南アジアはいいかなー。。。。次は、台湾へGo!

現場からは以上です。

北九州市気に入った! 宿泊と移動が一石二鳥 名門大洋フェリー 新門司港→大阪南港

先日、福岡→大阪の連続出張がありまして、僕が住む愛知県からはどういくのがいいのか?ということを考えていたら船を使うのがいいのでは?という結論に達して、実行してきたレポートです。

日程

8/7 福岡市博多駅付近にて某ボランタリーチェーンより依頼の7時間ぶっ通しセミナー
8/9 大阪南港地域のクライアントにてITコンサルティング

という日程でした。
8/6の夜には福岡に入っておく必要がある、8/8は空きではあるが、名古屋に帰るのはナンセンス。ということで、8/6の夜中部国際空港を発で、8/8のうちに大阪に移動、8/9夜帰宅。というイメージで調べていたところ、福岡と大阪を結ぶ海の定期航路があることがわかったので使ってみようということになったわけです。

8/6 ANA 449便 名古屋(中部)-福岡 20:10-21:35(この便はタイ国際航空などのコードシェアです)
8/6-8/8 福岡市内宿泊
8/7 セミナー登壇
8/8 北九州市小倉に移動し、19:50よりから船便
8/9 08:30 大阪南港到着

ANA449便のコードシェアや運用機材、福岡市内の宿泊などについては、特徴的なものをあえて選んで移動していますが、これについてはまたそのうち。

北九州市

8/8のホテルチェックアウトから、船便出航時刻の19:50までは時間がありましたので、博多駅から小倉駅に移動し、1日小倉の駅周辺でPCを開ける場所にて仕事をする予定でおりました。あまり調べずに福岡に向かい、前日に調べたところ、北九州市と呼ばれる地域はとても広いことを知り、小倉と門司は近いものの、門司港と新門司港は山で隔てられてなかなかに距離があり、小倉と近いのは門司港のほうで、僕が船に乗るのは新門司港の方だということがわかり、ちょっと焦りました。。。。
幸いなことに小倉駅から無料送迎バスがでています。よかったー(でもバスで40分!?)

小倉駅からすぐのところに1日利用で1000円のコワーキングスペース秘密基地さんがあったので、そちらを使うことに。

こんなかんじの雰囲気。夜はダイニングバー経営になるみたいですが、最近はシェアオフィス寄りなコワーキングが多いのですが、こちらは原義なコワーキングを感じました。

昼食は、どうも鉄鍋餃子で有名店があるということで、いくことに

総本店でした。実はわたくし、どうも最近では「唐揚の人」みたくなっていますが、某ミシュラン・ガイドにのった餃子専門店の主人に「博士」と呼ばれるほど餃子好きでして・・・行ってまいりました。評価は別のタイミングで。


北九州市民が博多になくて小倉にあるものとして胸を張るという、小倉城の横には、名古屋になり水辺のおされなコメダがありました(が、僕はコーヒーが苦手なのでめったに行きませんが)。商店街にはさまざまな種類のお店があり、活気もそこそこ。北九州気に入りました。

いよいよ出航

18:30になり、新門司港へいくバスが小倉駅から出ますので、バスにのって新門司港へGoです!。40分のバス。19:50に船が出ますので、このバスが、航路の一部分と言えます。バスの道すがら門司港も通りまして、門司港もレトロで良い雰囲気ですね。

今回乗る船はフェリーで名門大洋フェリーという会社が1日2往復運行しています。「名門」ってなかなか自己主張が強い名前だなと思ったら、昔は名古屋と門司港を結ぶ定期航路を運営していた会社で、そこから「名門」とついたようです。なんかすみません。
ちなみに。新門司港からは「阪九フェリー」という会社の船も出ているようですが、こちらは大阪が泉大津に着くので、大阪市からはちょっと遠くなります。

今回利用する便は、新門司港19:50発 大阪南港フェリーターミナル08:30着という 移動と宿泊が一石二鳥で終えることができるベストな便です。いわゆる雑魚寝から個室まであります。今回はカプセルホテル的なクラスがあるので、そちらを利用しました。

食事は付いていませんが、片道6200円で移動と宿泊が一気に行えるのはとても便利です。

船内

19:50定刻通り出航!

(標準時刻ではない実際の)時差では愛知県と20分くらいの差があり、19:50はちょうど日暮れの時間です。左手には北九州市の山々、右手には北九州空港を見ての出航です。清々しいですね。


昨年いったクルーズ船の旅よりは小さいですね。当たり前ですけど(しまった!続編の記事書いてない!!) 一つ良いのは浴場があって、大人の男が7人位入っても大丈夫くらいの湯船のある浴場です。小さい船なのでエンジン音はどうかなーと思いましたが、全然気にならないですね。揺れもあまり気になりません。晴天ということもあるでしょうけれども。



食事は夜1500円朝700円のバイキング方式。バイキング方式なのであまり期待していませんでしたが、思ったよりは美味しいものがそろっており、定期航路だからなのか企画も考えられていて、今回はビンチョウマグロと甘海老が食べ放題でした。悪くないですね。


生ビールは、1杯500円で売っています。売店でもお酒などは売っています。

この船には、ラウンジ的なものはなく、小さいテレビを見るスペースと展望スペースがあるくらいです。クルーズ船とちがって、車を運ぶため駐車スペースが多いからでしょう。

船内にはwifiがあります。1日30分3回まで使うことができます。0時で次の日の扱いとなるため、この船では合計3時間までつかうことができます。この航路は瀬戸内海を通りますので、人口がある地域を通っていることになりますから、比較的安定して電波をつかみます。しかし、客室は船という性質上 壁がかなり堅牢に作られており、客室には船内wifiが届きにくいです。 僕が普段持ち歩いているauのデータ専用SIMとほぼ同じ強さを示していたので、船内wifiの大元は、au系の回線であろうかとおもいます。

大阪南港はユニバに近いこともあり、九州方面からユニバに遊びに行く家族連れ、夏休みの時期ということもあり、大学や高校の部活の合宿の行き帰りの団体、トラック運ちゃんが多いようでした。ビジネスマンはすこしだけいましたが、航空や新幹線に比べると比率は少ないです。

クルーズ船とちがい、夜に遊ぶ要素はありませんし、8:30には下船をすることを考えると6:30には起きてないといけませんから、寝るのを早くする人が多いです。カプセルの部屋にテレビもありませんしね。



朝になると、少ないビジネスマンたちが今日の仕事の準備をしています。7:00ごろには、明石海峡大橋をくぐり、阪神工業地帯を眺めながら、大阪へのアプローチとなります。

7:50くらいにはパイロットが近づいてきて大阪南港への最終アプローチ。時間通り8:30に南港へ下船開始となります。

なお、船では「パイロット」は操縦士ではなく水先人のことです。航空では「アビエイター」が元々の操縦士ですが、現在は「パイロット」で通じます。ただし、空海両方の事業に関わる人との間ではpilotとaviatorは使いわけることが多い。ビジネス用語としては両方知っておいたほうがいいですね。

大阪南港フェリーターミナル

大阪南港フェリーターミナルは、大阪市内ではあるものの少々不便なところにあります。公共交通機関では、大阪市高速電気軌道南港ポートタウン線(ニュートラム)駅がありますが、梅田周辺までは、乗り換えが2回発生し、およそ50分程度かかります。ユニバーサル・スタジオジャパンまではバスが出ており30分程度かかります。

今回良かったのが、南港フェリーターミナルと出張先のクライアントの本社が歩いて10分程度のところにあるためアクセスが良かったためつかいましたが、たとえば梅田周辺で10:00からのアポとなると、ちょっと時間的には危険な感じもします。アポ時間と行かなくてはならない場所によっては、出張で使うのはリスクが伴います。そういったいみでも、今回はレポートを書いておこうと思ったわけです。

現場からは以上です!

「超読」の世界を見てきた。

どうもこんにちは 伊藤です きよっちです。

おひさしぶりです。いい加減書けよ。とクライアント各位には叱られそうですが。。。

さて、昨日2019-07-12に「超高速読書法(略称:超読)」という、一般的には「速読」と言われるものの体験会があったので、いってきました。参加費は5000円と決して安くはないのですが、これはなかなかカルチャーショックだったので書きます。

http://cho-doku.com/
↑こちらが公式?(トップページタイトルが「top」だよ!書き換えよ!!)
http://cho-doku.com/seminars/
↑こちらが体験会の案内ページ。

僕の速読の前提知識

速読というのは、何十年も前からビジネスや勉強のスキルとして、存在しているのは当然知っていましたが、何なのかは全く知りませんでした。
この体験会に参加するにあたり、いくつかのYouTubeやサイトの情報をチェックしてはおきました。

  • 一瞬で文字を判断できるように、本を読む上で、その本から得たい答えの問いを持っておく
  • 飛ばし読み斜め読みをする

が「一般的には多そう」でした。
なるほど。これならば「都合のいい情報だけをピックアップする」という人間の脳構造の特性である「確証バイアス」に近い考えなのでできなくはない?感じはしました。

が、結論から言うと、超読は

これらとは一線を画す「ちゃんとした読書」でした!!

超読は技術理論

体験会では、その名前の通り、超読の玄関口となる技術を体験体感する会となっていました(ネタバレになるので書きません)。前述の「一般的な速読」はどちらかというと「要約するための考え方」というほうが正しくて「読む」ということとは別の概念なのかな?とおもいます。 それに対して超読は、早く読むための身体コントロール技術でした。つまりは、まさに「読む」という行動そのままです。

体験会の案内ページに「感情移入しながら小説を読める」とありますが、まさにこれだなと。要約の方法では、行間を読む事はできませんから。僕は仕事柄、平均すると月間で10冊超えるくらいの技術本とビジネス本を読みますが、これらも行間が読めないと、ほとんど役にたたないと思っていますので(そもそも日本語の構造がそうなってる)、何も小説に限った話ではない、本を読むためのベース技術だろうなとおもいました。

しかし身体コントロール技術なので習得の難易度はそこそこ高そうでもありました。(毎週受講で3ヶ月必要。その後の追加補講はいくらでも通っていいらしい)

怪しくないのか?

ぶっちゃけると、怪しいです(笑) いや、体験会で体験すること、聞くことはまったく怪しくなく、むしろ、納得できるものがとても多いのです。 しかし、超読を習得・修得している、みなさんが「変わっている」のです。これはポジティブな意味で、普段の生活で速読の技術は「必要条件」かといわれると、そんなことはなく、単純なニーズと言う意味では速読は不要と言えます。それをわざわざできるようになって、自分のライフスタイルに厚みをつけようと考えている人たちなわけですから、変わっているとしか言いようがありません。でも、明確なのはふんわりとした精神論や自己啓発より、はるかに意味があることをやっている(し、そういったことは、身体技術としての超読を身に着けて、本を読む中で見い出せばいいのでは?)のは、すごくわかりました。なので、やるかやらないかは別として体験会にだけでもいってみる価値はあると言えます。

ぼくだけの感想

今回の体験会では、僕の友人が実演をしてくれました。彼女の目の動きや身体の使い方を目の当たりにしたのですが、その感想は、「梅原大吾と同じ目をしている」でした。

梅原大吾は、日本のeスポーツの第一人者で、対戦格闘ゲームで世界に知られるプレーヤーです。対戦格闘ゲームは、決まった座標範囲内で、周辺視野を広くとり、1/60秒で情報取得し判断するというゲーム性で成り立っています。心拍数コントロールや筋肉の使い方制御など、ビデオゲームといえど、ほとんどやることはスポーツと変わりないです。

これを3ヶ月で身につけられるとなると、超読は何か分野において世界に行ける可能性のある技術だなと思いました。

ところであんた習うの?

かなりやりたいとおもっています。

が、決して安くはない本セミナー受講料(高いといっても安いんですが)、そして東京でしかいまのところやってない。
というのがあるので、準備をしなければ。。。。まずは東京でコンサルティングの仕事を1つばかり増やしたいなと。

で、作る仕事はとりあえず2020年4月くらいまではストップします宣言!します。

P.S

開発者の先生がマイルオタクだったので、ぼくはそこにも惹かれています。

現場からは以上です。

楽天の注文フォームに無茶させるver.2.1 スマホ対応

どうもどうもおひさしぶりです。伊藤です。
全然ブログ書かねぇじゃねぇかとクライアント各位に叱られそうですが、全くそのとおりでございます。

昨年、楽天の注文フォームにむちゃさせるver2という記事を書きました。が、この記事少しだけ不具合がありました。ので、それを修正するお話。

スマホ対応

不具合の具体的な内容は、スマートフォン対応です。スマホの場合は少しだけパラメータが追加になります。

あ、その前にPCの場合の対応は、以前の記事を見てくださいね。

ちょっとだけ難しい話をきかきますが、スマホ時は、以前の方法だと、カゴにはいったと処理完了のステータスが楽天側からリターンがあるにもかかわらず、カゴにいくと中身がなくなってしまうという不具合があります。どうも楽天のスマホのカートシステムは、URIから制御を取得しているらしく、あらかじめ専用セッションにカートの追加命令が保存されていないと、URIの処理が優先されて、カートが空になるという仕様になっているようです。

AJAX送信時にパラメータ追加

結論から言えば、

$.ajax({
  url: 'http://direct.step.rakuten.co.jp/rms/mall/cartAdd/',
  type: 'get',
  dataType: 'jsonp',
  data: {
      'shopid': ショップID(整数値),
      'units': 個数(整数値),
      'itemid': 商品番号(整数値),
      'device': 'sp',//デバイスモードをスマホに
      'userid': 'itempage',//これがないとカゴにはいらないときがある???
      'dbasket_choice_select[]': 'オプション文字列',
      'dbasket_choice_select[]': 'オプション文字列2'
  }
})
.then(function(data){
  if( data.resultCode == '0'){
    alert('OK');
  }
  else{
    alert( 'error!: ' + data.resultMessage );
  }
});

というパラメータになります。つまり device=sp と userid=itempage が追加になっているということです。
レスポンシブでページを作っている場合は、これをPCスマホ時で切り替える必要があります。

なんでもいいけど、カート追加がGETで行われる楽天さん。まじでイケてないんでHTTP勉強しなおしてください!!

SPとPC切り替え

User-Agentなどで判定すればOKです。といってもわからない方もいらっしゃるとおもうので、ページは重たくなりますが、判定ライブラリを使った場合の例示も書いておきます。

HTMLに自作JSファイルをの前に

<script src="https://cdnjs.cloudflare.com/ajax/libs/mobile-detect/1.4.3/mobile-detect.js"></script>

を呼び出します。ライブラリの詳細はこちらをごらんください。

JSファイルは以下のようにします。


///パラメータ
var params = {
      'shopid': ショップID(整数値),
      'units': 個数(整数値),
      'itemid': 商品番号(整数値),
      'dbasket_choice_select[]': 'オプション文字列',
      'dbasket_choice_select[]': 'オプション文字列2'
  };

///モバイル判定
var md = new MobileDetect(window.navigator.userAgent);
if( md.mobile() != null ){
  params['params'] = 'sp';
  params['userid'] = 'itempage';
}

///ajax実行
$.ajax({
  url: 'http://direct.step.rakuten.co.jp/rms/mall/cartAdd/',
  type: 'get',
  dataType: 'jsonp',
  data: params
})
.then(function(data){
  if( data.resultCode == '0'){
    alert('OK');
  }
  else{
    alert( 'error!: ' + data.resultMessage );
  }
});

以前の記事で書いていないことがありました。カゴへ移動

処理完了時にカートへ移動したいということがあると思いますので、そちらをいれたバージョンも書いておきます。


///パラメータ
var params = {
      'shopid': ショップID(整数値),
      'units': 個数(整数値),
      'itemid': 商品番号(整数値),
      'dbasket_choice_select[]': 'オプション文字列',
      'dbasket_choice_select[]': 'オプション文字列2'
  };

///モバイル判定
var md = new MobileDetect(window.navigator.userAgent);
if( md.mobile() != null ){
  params['params'] = 'sp';
  params['userid'] = 'itempage';
}

///ajax実行
$.ajax({
  url: 'http://direct.step.rakuten.co.jp/rms/mall/cartAdd/',
  type: 'get',
  dataType: 'jsonp',
  data: params
})
.then(function(data){
  if( data.resultCode == '0'){
     location.href = 'https://ts.basket.step.rakuten.co.jp/rms/mall/bs/cartall/?shop_bid=ここにショップID';
  }
  else{
    alert( 'error!: ' + data.resultMessage );
  }
});

location.hrefを使ってショップIDを指定したカートURLにページ移動させることでカートへ遷移します。

動作参考をば

そういえばこれまえ参考動作を作っていませんでしたね。動作させてみましょう。



辛いものをカゴにいれる

↑ここをクリックするととっても辛い商品がカゴにはいるよ!!!

で何をしているかというと

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mobile-detect/1.4.3/mobile-detect.js"></script>
<script>
$(document).ready(function(){
    var md = new MobileDetect(window.navigator.userAgent);
    
    $('.btn-send-rakuten').on(
        'click',
        function(eve){
            setProduct(0);
        }
    );
    
    var productList = [
        { 'shop_bid': '205607', 'item_id': '10002002', 'option': 'とってもからいよ!' },
        { 'shop_bid': '205607', 'item_id': '10002166', 'option': 'こっちもすごいよ' },
    ];
    
    function setProduct( current ){
        var targetProduct = productList[ current ];
        var params = {
            'shopid': targetProduct['shop_bid'],
            'units': 1,
            'itemid': targetProduct['item_id'],
            'dbasket_choice_select[]': targetProduct['option']
        };
        if( md.mobile() != null ){
          params['params'] = 'sp';
          params['userid'] = 'itempage';
        }

        $.ajax({
          url: 'http://direct.step.rakuten.co.jp/rms/mall/cartAdd/',
          type: 'get',
          dataType: 'jsonp',
          data: params
        })
        .then(function(data){
             current ++;
             if( current >= productList.length ){
               location.href = 'https://ts.basket.step.rakuten.co.jp/rms/mall/bs/cartall/?shop_bid='+productList[0]['shop_bid'];
             }
             else {
                setProduct( current );
             }
        });
    }

});
</script>
</pre>
<a href="javascript:void(0);" class="button is-danger is-fullwidth btn-send-rakuten">辛いものをカゴにいれる</a>

こんなコードです。

  1. カートに入れたい商品を配列で準備
  2. カートに入れたい商品をループ(ここで関数自体を回帰呼び出し)してAjaxコール
  3. 全商品はいったらカートにジャンプ

です。JSの書き方としては、あえて古い書き方でわかりやすくしているので、JSプログラマ諸氏はご勘弁を。

1フォームで楽天で複数商品をカートに入れる方法は他にもありますが、動的にPC/SP共通でカートに入れられるというのは、サイトの表現上役に立つことが多いかと思います。

現場からは以上です。

さくらインターネットのMySQLが5.7になってORDER BYでこまったとき

古いWebアプリケーションフレームワークをつかい
MySQL5.6までのMySQLデータベースをつかったアプリケーションを
MySQL5.7のサーバーに移転するにあたり

ORDER BY clause is not in SELECT list, references column...

というようなエラーが出た場合、MySQL5.7より「ONLY_FULL_GROUP_BY」がオンになっていることが原因だ。

このあたりは、すでに多くの先駆者が設定について書いてくださっている。

など。大変ありがたい情報だ。

しかし、さくらインターネットでは権限がない

さくらインターネットなど共有サーバーでは、これらの設定については、
権限付与がなく設定ができない。

さてどうしたものか。。。

そのセッションのみで、(MySQL Workbenchをつかっている経験から)SQLMODEの変更ができるはず。
ということで

SET SESSION sql_mode = 'NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

毎回接続時に実行できればOKなはず。と考察して、調べた結果問題なしでした。
各フレームワークや、自作のシステムの場合も、
mysqli_connect関数の直後や、new PDO()直後あたりで毎回実行するようにすればOKです。

WordPressでタイトルタグをテンプレートファイル側から指定

今日はかりゆしウェアを着ている伊藤です。どうもどうも
2018年日本は災害レベルで暑いですね。沖縄県はすずしいですよ。

さて最近連日WordPressの話題を書いています。
今日はWPのタイトルタグをテンプレート側から指定できるといいよね~ってはなしをします。

おともだちのKさんの記事を参考にして書いていきます。

前提条件

  • 包括的に全部を書き換えるのではなく、必要なタイミングでテンプレートごとに指定したい
  • テンプレートファイルからは、get_header();の直前に関数で指定したい

たぶんあるあるだと思います。SEO考えるとね。結構いじりたいところですからね。

document_title_partsフィルターを利用する

Kさんの記事によると、document_title_partsに紐づけした関数に、引数としてタイトル構造を持つ配列が渡されて、それを編集してreturnすればいいぜ。ワイルドだろー?って書いてあるます。なるほど。しかし僕のやろうとしていることだと、必要なタイミングで呼びたいという前提と、テンプレート側から指定したという条件が入るので、そのまんまは使えません。
そこで登場するのがクロージャーです。

クロージャーを使って実装

もうめんどいからソースを晒します。functions.phpにでも書いてください。

/**
 * タイトル変更
 * @param string $title
 * @param string $tagLine
 * @param string $siteTitle
 */
function setTitle( $title, $tagLine = null, $sitTitlte = null ){
    add_filter(
        'doment_title_parts',
        function( $return ) use ( $title, $tagLine, $sitTitlte ) {
            $return['title'] = $title;
            if(!is_null($tagLine)){
                $return['tagline'] = $tagLine;
            }
            if(!is_null($sitTitlte)){
                $return['site'] = $sitTitlte;
            }
            return $return;
        }
    );
}

こんかんじ。で、テンプレからは

setTitle( 'たいとるだよーん' );
get_header();

もう少しちゃんとするならクラスにして静的メッドにするのが筋でしょうねー。
クロージャーをつかっています。あんまりWPでは使われないかとおもいます。

意外に使うTipsになるのでは?
現場からは以上です。

WordPressにORMを組み込む

どうもどうも。2年近く連絡をしていなかったら育ての親である叔父が心配してきた伊藤です。

さて、WordPressにはデータベースを操作する機能というのは一応揃っています。
wpdbとかそのへんですね。ただ、基本的にはSQLを書くか、あるいは、WPのもともとのテーブル構造に対するクエリを前提としていることが多く、遠回りだったりとかしますわね。できればActiveRecordやORMがはいっているといいなーと思うわけです。

特に、従前のシステムがあって、WPでリニューアルをかけたい。というときは、従前のシステムのテーブルはそのままにリニューアルをしたいということは、多々あるわけです。

まさにそんな事を考えていたので、いっちょWordPressにORMを入れてみた。というはなしをします。

PHPのActiveRecord ORMライブラリ

PHPのActiveRecordやORMの単体ライブラリというのが、実はそもそもあまりないです。最近のPHPのフルスタックWebアプリケーションの場合、Doctrineがベースに利用されていたりとかするわけで、車輪の再開発を嫌うのか、あまりないのです。

僕の場合は、PHP5.3系の頃は、php-activerecordをよく使っていましたが、ちょっと古くなったのと、リレーションのリレーションが追えないなど、ちょっと足らないところもあります。

今回探していていい感じだなーとおもったのが、RedBeanPHPです。MySQL/MariaDBのプラグインとPHPライブラリを提供しており、かなり高速で、わかりやすいコード体系のORMになっています。しかし、MySQLのプラグインということで、共有ホスティングなどでは可搬性がさがりますので、今回は見送りました。

今回採用することにしたのがSpotORMです。Doctrine DBALをベースに作られたORMラッパーです。Relationの定義などがしやすく、僕がよく使うフレームワークYiiのModelの構造に似ているのも、採用の理由です。

ではインストール

composerでインストールします。

{
    "require": {
        "vlucas/spot2": "~2.0"
    }
}

とかですかね。composerの使い方はぐぐれ。

WPの場合は、functions.phpにコードを書く感じになるので、テンプレートディレクトリで実行すればよいかと思います。で、functions.phpの冒頭くらいに

require __DIR__.'/vendor/autoload.php';

とでも書いておけば良し。インストールが簡単です。

つかってみましょう

まず接続設定をします。

$cfg = new \Spot\Config();
$cfg->addConnection( 'mysql', 'mysql://ユーザー:パスワード@ホスト名/DB名' );
$spot = new \Spot\Locator($cfg);

DSNで書くとこんなかんじ。連想配列での指定ももちろん可能です。
設定はWPの接続情報を使い回すとかでもいいでしょう。

モデルを用意する

ORMなのでモデルクラスを用意します。
僕の場合は、functions.phpの並びに「Entity」フォルダを用意して、その中にモデルクラスを配置しました。オートローダーをとかを作るほどでもないので functions.phpに

$files =  glob( __DIR__ .'/../Entity/*.php') ;
if(!is_array($files)){ $files = array(); }
foreach( $files as $one ){
    require_once $one;
}

を追記します。
Entityの中身を一気にロードしちゃっています。もちろん必要時に読むというやり方のが正しいとは思います。

Modelファイルの中身は

 ['type' => 'integer', 'primary' => true, 'autoincrement' => true],
        ];
    }
}

仮にこんなかんじです。fieldsになにかないと怒られることがある?っぽいので、primaryのIDだけ定義しておきました。

呼び出しに使ってみる

最後に実際にDBにクエリしてみましょう。
呼び出しをするfuncitonの中で

function hoge(){
    global $spot;
    $postMapper = $spot->mapper('Entity\Products');
    $row = $postMapper->where([
        'item_id' => '品番'
    ])->first();
    return $row;
}

こんな感じにかきます。上記例では商品DBに品番を問い合わせる。的な事をしています。

実際組み込んでいるがWPと融合しているわけではない

ここまで読むとPHPerならおわかりになるとおもいますが、WordPressのオブジェクトの他に、DBに対して接続を一つたてることになります。したがって、メモリ効率などは悪くなります。手軽さと、パフォーマンスどちらを優先するかなどで、選択することになるとおもいます。
しかし、DB操作をして、サイトデザインをWPに合わせるなどを考えると、有用ですし、SQLを書くよりはセキュリティ面でも安心してかけますね。

現場からは以上です。

超簡単なテンプレートエンジン(条件分岐なし)ならCodeigniterからパクれ

どうもどうも。今年はそこそこブログを書いています。体調が戻ってきました。よかったよかった。決して万全ではないのですが、1年近く体調がわるかったので、まぁそのいろいろアレです。

ところで、PHPerのみなさん。
たとえば、管理画面でメールテンプレートを管理するような場合、
そのテンプレートをどう処理するか、結構悩みますよね。

同じようなかんじで、WordPressなんかで、囲みタグ型のショートコードでループをさせたいときとかもかなり悩みます。

よくある例だと、

  1. 管理画面からテンプレート編集
  2. POSTされたデータをDBに保存しつつ、テンプレートエンジン用に、ファイルにも保存
  3. 出力時に保存されたファイルをテンプレートエンジンで処理して出力

というような手順でしょうか。
まぁ悪くはないですが、セキュリティに気をつけなければいけないとか、結構手間取りますし、ファイル出力だと手軽さがなくなります。

今回はWordPressのショートコードでどうしようかなーと思ったときの対処をメモ代わりに。

やりたいこと

前提条件です。

  • WordPressの囲みタグ型ショートコードをテンプレートとして扱いたい
  • テンプレートエンジンとして動かしたいが、PHPを書くのや、Smartyのようにファイル処理を前提としない
  • 条件分岐はとりあえずいらないがループはある

という前提条件で、具体的には

[get_product_categories category="カテゴリ名"]
<ul>
    {categories}
    <li>
        <a href="{category_url}">
           {category_name}
        </a>
    </li>
{/categories} 
</ul>
[/get_product_categories]

こんなショートコードを書いてもらってテンプレート処理をしたいわけです。
囲みタグ型のショートコードについてはみなさまが書いているので、そちらをご参考に

まぁ普通にやれば

このような条件を満たそうと思うと、難しいコードでもないので、自分で簡単なテンプレートエンジンを書いてもいいとは思うのですが、いまいち気乗りがしません。自分で書くとすれば、正規表現を書いて、ゴニョゴニョとするところではありますよね。

そこで!Codeigniterの簡易パーサークラスをぱくってきます

Codeigniterには条件分岐はないですがループに対応して、ファイル処理なしで実行できる簡易テンプレートンジンがついています。これが使えないかと思ってソースを見たところ、Codeigniter本体にはほとんど依存していないことがわかり、少しの書き換えで対応ができることがわかりました。

四の五の言わずにコードを晒せ

はい。

<?php
class CI_Parser {

    /**
     * Left delimiter character for pseudo vars
     *
     * @var string
     */
    public $l_delim = '{';

    /**
     * Right delimiter character for pseudo vars
     *
     * @var string
     */
    public $r_delim = '}';


    // --------------------------------------------------------------------

    /**
     * Class constructor
     *
     * @return void
     */
    public function __construct(){
    }

    // --------------------------------------------------------------------

    /**
     * Parse a template
     *
     * @param  string
     * @param  array
     * @param  bool
     * @return string
     */
    public function parse( $template, $data, $return = FALSE ){

        return $this->_parse($template, $data, $return);
    }

    // --------------------------------------------------------------------

    /**
     * Parse a template
     *
     * Parses pseudo-variables contained in the specified template,
     * replacing them with the data in the second param
     *
     * @param  string
     * @param  array
     * @param  bool
     * @return string
     */
    protected function _parse( $template, $data )
    {
        if ($template === '')
        {
            return FALSE;
        }

        $replace = array();
        foreach ($data as $key => $val)
        {
            $replace = array_merge(
                $replace,
                is_array($val)
                    ? $this->_parse_pair($key, $val, $template)
                    : $this->_parse_single($key, (string) $val, $template)
            );
        }

        unset($data);
        $template = strtr($template, $replace);

        return $template;
    }

    // --------------------------------------------------------------------

    /**
     * Set the left/right variable delimiters
     *
     * @param  string
     * @param  string
     * @return void
     */
    public function set_delimiters($l = '{', $r = '}')
    {
        $this->l_delim = $l;
        $this->r_delim = $r;
    }

    // --------------------------------------------------------------------

    /**
     * Parse a single key/value
     *
     * @param  string
     * @param  string
     * @param  string
     * @return string
     */
    protected function _parse_single($key, $val, $string)
    {
        return array($this->l_delim.$key.$this->r_delim => (string) $val);
    }

    // --------------------------------------------------------------------

    /**
     * Parse a tag pair
     *
     * Parses tag pairs: {some_tag} string... {/some_tag}
     *
     * @param  string
     * @param  array
     * @param  string
     * @return string
     */
    protected function _parse_pair($variable, $data, $string)
    {
        $replace = array();
        preg_match_all(
            '#'.preg_quote($this->l_delim.$variable.$this->r_delim).'(.+?)'.preg_quote($this->l_delim.'/'.$variable.$this->r_delim).'#s',
            $string,
            $matches,
            PREG_SET_ORDER
        );

        foreach ($matches as $match)
        {
            $str = '';
            foreach ($data as $row)
            {
                $temp = array();
                foreach ($row as $key => $val)
                {
                    if (is_array($val))
                    {
                        $pair = $this->_parse_pair($key, $val, $match[1]);
                        if ( ! empty($pair))
                        {
                            $temp = array_merge($temp, $pair);
                        }

                        continue;
                    }

                    $temp[$this->l_delim.$key.$this->r_delim] = $val;
                }

                $str .= strtr($match[1], $temp);
            }

            $replace[$match[0]] = $str;
        }

        return $replace;
    }

}

Codeigniterのコントローラーオブジェクトに依存しているところなどを削って純粋にclassとして動くようになっています。

じゃWPで動かしてみよう

functions.phpあたりで、上記ファイルをrequireして

add_shortcode( 'get_product_categories', 'get_product_categories');

functionget_product_categories( $atts, $content = null ){

    //このへんで適当に引数処理してね    
        
    $parser = new CI_Parser();
    $args = array( ここに適当に条件かいてね );
    $the_query = new WP_Query($args);
    if (!$the_query->have_posts()) {
        return '';
    }
    
    $data = array();
    $data['categories'] = array();//ショートコードのループタグと名前を合わせる
    while ( $the_query->have_posts() ) {
      $the_query->the_post();
      $set = array(
        'category_name' => get_the_title(),
        'category_url' => get_the_permalink(),
      );
      $data['categories'][] = $set;
    }
    wp_reset_postdata();
    
    
    $content = $parser->parse( $content, $data );//最後にパースする。
    return $content;
}

とでもしておけば、簡単ね。

多分改造でifくらいはいける

上記の通りCodeigniterのパーサーはシンプルにできてます。
たぶん改造すればifくらいは余裕でかけると思います。
が、他方、毎回実行時にパーサーが走るわけなので、決して軽くはありません。
使い所見極めていきましょう。

なお、Codeigniter3.xはMITライセンスなのでOKですが、2.xまでのコードを使う場合は独自ライセンスなので、扱いに気をつけてください。

現場からは以上です。

楽天PayオーダーAPIをPHPからコールしてみた

どうもこんにちは伊藤です。きよっちです。半年ぶりの更新となりました。真面目に書けよ!と思われるかもしれませんが、まったくそのとおりですね。ちょっといろいろ思うところがございまして、沈んでましたが、それはまたおいおい。

はい。ところで。楽天さんの動きが激しいですね。楽天Payへの移行などなど。やらなくてはいけないことがたくさん。ちょうど今年2018年はヤマト運輸さんの配送料金大改革などなどもありましたし、Instagram上で通販が可能になったりしましたし、環境は大きく揺れ動いています。日本のECがはじまって以来、最も大きな変革期に来ているのかもしれません。ECを主戦場にしている業者さんは、自社の立ち位置、目指す場所、戦い方(戦わないという選択肢も含めて)などを明確にできる機会かもしれません。

ちょっと話がズレてしまいましたが、さて、楽天は改革を迎えているわけで、個人情報の扱い厳格化、決済方法の統一化などがあり、なるべく多くの受注操作をRMS上で行わなければならないようになってきています。

そんなこともあり、最近では、自社開発DBとの連携のために、RMS Web Service APIを利用しなければならないということもかなり増えてきました。今日はそのお話です。

RMSのAPI

まず、もってですね、楽天のRMSのAPIというのは、みなさんご存知でしょうか。2012年ごろからスタートしているRMS用のAPIです。それより以前は、公開情報(つまり商品情報ですね)を取得して、楽天外のwebサイトで活用できるようになっていたわけですが、RMS APIができてからは、RMSを楽天のシステム外で利用できるようになっています。(もちろん自社運営の楽天サイトの情報しかとることはできません) 経緯はこのあたりにくわしいです。

このRMSのAPIというやつがですね、わたしたちwebをメインにしているエンジニア・プログラマには、あまり馴染みのない「SOAP」という規格のAPIを採用しています。こいつがなかなか厄介で、webで多く使われているPHPでは、コードが冗長になりがちなのです。

そのコードについてはこちらのサイトにてサンプルが書かれていますので、参考になります。わたしも最初は参考にしました。

楽天PayOrderのAPI

上記のように、まぁぶっちゃけて言うと大変に分かりづらいSOAPを仕様したRMS APIなんですが、一回実装してしまえば、そうそう変更するものでもないので良しとしていました。

ここからが本題です。

ところがですね、楽天Pay移行により注文情報取得APIを変えなければならなくなりました。2018年以降、楽天各店は決済方法統一のため楽天Payに強制移行となりますので、既存APIを利用していた事業者さんは、いずれ、のりかえが必要ということです。 楽天Payへの移行については、こちらの記事がよくまとめられています

しかし、文句ばかりも言っていられませんので、楽天へ出店しているクライアントさんのために、API改造に着手しました。いつもそうなんですが、楽天さんのエンジニア向けドキュメントは、ぜんぜんまとまってなくて、どこにいけばわかるのかがわからない。たどり着いたとしても、実は全体像はそこだけではわからない…など前途多難なのです。

とりあえずドキュメントにたどり着いたので、従前のOrderAPIを書き換えてみる。

…あれ…なんか変だ…動かない…というよりは、楽天から返ってくる書式が変だ…
…ん???
…あれ??????
(ここまで1時間)

ようやく気付いたのですが、楽天PayOrderAPIだけが、基底となっている技術そのものを変えてきやがったのです!!!もう「やがった」といいますが許してください!

よく読めと言われれば、それまでですが、楽天PayOrderAPIだけは「JSONベースのSOAP」なのです。APIさわったことのあるエンジニアならわかるとおもいますが「お前何いってんだよ!」ってなりました。「SOAP」はもともとXML通信インターフェイスだろうよ!!!リクエストもレスポンスもJSONでやるのに、技術そのものはSOAPなのです。この矛盾に気づくのに時間がかかりました。(ここから想像するに、おそらく楽天PayのAPIの基底フレームワークはIBMのCICSだと思われます。もう少し標準的な仕様にしてくれませんかね???)

とっととコードを出せ

はい。。。ごめんなさい。。。取り乱しました。

class RMS {
    
    public static $serviceSecret;
    public static $licenseKey;
    
    // ----------------------------------------------------
    /**
     * オーダー取得
     */
    public static function searchOrder(){
        
        ////認証キーを作成
        // oAuthのが1289倍楽なんですけど!!!
        $authkey = "ESA " . base64_encode( self::$serviceSecret . ':' . self::$licenseKey );
        
        ////検索日付
        // そんなもん必須にせずに良きに計らえや!!!!
        // しかもいちいちGMTに変換しなきゃあかんのかい!!!それも良きに計らえよ!!!!
        // 第二引数で日本時間指定できるようにしておいた
        $beginDate = gmdate( 'Y-m-d\TH:i:s+0900', strtotime('2018-07-05 00:00:00'));
        $endDate = gmdate( 'Y-m-d\TH:i:s+0900', strtotime('2018-07-29 00:00:00'));
        
        //// なぜか楽天ペイAPIだけ しかも形の上ではSOAPなのに JSONでリクエスト…
        // 統一してくれんかな!!!ライブラリ書くのめんどくさいんだけど!!!!
        $requestJson = json_encode([
            'dateType' => 1,//期間検索種別
            'startDatetime' => $beginDate,//検索対象期間先頭日時(普通startじゃなくてbeginじゃねぇか??)
            'endDatetime' => $endDate,//検索対象エンド点
            'orderProgressList'=> [ 100, 200, 300, 400 ],//取得したいオーダーステータス
        ]);
        
        
        //// リクエストヘッダ作成
        // うーん なんかこの認証いまいちだなー・・・
        $header = [
            'Authorization: '.$authkey,
            'Content-Type: application/json; charset=utf-8',
        ];
        
        
        //// SOAPリクエスト
        // この辺はREST APIでのPOSTと一緒。ただし、レスポンスコードで結果コードをとるので
        // レスポンスヘッダについては厳重目にとっておくべき。
        $url = 'https://api.rms.rakuten.co.jp/es/2.0/order/searchOrder/';
        $curl = curl_init($url);
        curl_setopt( $curl, CURLOPT_POST, true );
        curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
        curl_setopt( $curl, CURLOPT_HTTPHEADER, $header );
        curl_setopt( $curl, CURLOPT_POSTFIELDS, $requestJson );
        curl_setopt( $curl, CURLOPT_HEADER, true);//これを指定するとレスポンスにヘッダがついてくる
        
        // curlセッションを実行 ヘッダが付いているので分解
        $response = curl_exec( $curl );
        
        // ステータスコード取得
        $statusCode = curl_getinfo( $curl, CURLINFO_HTTP_CODE );
        
        // ヘッダサイズを取得して、その分を切り取ってしまう方策
        // もう少しいい方法があるかもしれない??
        $headerSize = curl_getinfo( $curl, CURLINFO_HEADER_SIZE );
        $requestHeader = substr( $response, 0, $headerSize);
        $requestBody = substr( $response, $headerSize );//ここに結果JSONがかえる
        
        
        //// jsonをオブジェクトにー
        $return = json_decode( $requestBody );
        
        curl_close( $curl );
               return $return;
        
    }
    
    // ----------------------------------------------------
    
}

ざっくりとclassにしました。モダンなコードではないですし、何かが漏れていますが気にしないでください。
引数でパラメータを指定できるようにするなどの改造は必要だとおもいますし、いくつかのエンドポイントを実装するにあたってはPOST部分を独立メソッドにすべきでしょう。そこは、皆さんのセンス。

このクラスをロードしておいて

<?php
RMS::$licenseKey = 'ライセンスキー';
RMS::$serviceSecret = 'シークレットキー';
$res = RMS::searchOrder();

とかでだいたい勝てます。

以上、現場からでした。
「室井さん。どうして現場に血が流れるんだ!」(←古い)

Older posts