tohokuaikiのチラシの裏

技術的ネタとか。

Confluenceのプラグイン開発を承ります。ご連絡はこちらのホームページからお願いいたします。

今更ながらPHP7でローカルにPEARを入れた話

今どきPEARって…という感じですが、HTTP_Request2とか意外と使い慣れてるので便利なんですよ。いい加減ComposerでGuzzle使ってくれって話なのですが、ことによってはHTTP_Requestの方がちょろっとPHPCLIスクリプト書く分には楽ですよね。と。

インストールは今どきは、go-pear.phpじゃない

インストールはgo-pearを取るんだったなと思いおもむろに

$ wget http://pear.php.net/go-pear
$ php go-pear

と打ち込んだところ

Sorry!  Your PHP version is too new (7.0.19-1) for this go-pear.
Instead use http://pear.php.net/go-pear.phar for a more stable and current
version of go-pear, more suited to your PHP version.

Thank you for your coopertion and sorry for the inconvenience!

ありゃりゃ。ということで、

$ wget http://pear.php.net/go-pear.phar
$ php go-pear.phar

としてインストール開始。

インストール場所の設定

どこにインストールするかを聞かれる。
ひっそりとこっそりとどこぞやの作業量ディレクトリに入れたいので

Below is a suggested file layout for your new PEAR installation.  To
change individual locations, type the number in front of the
directory.  Type 'all' to change all of them or simply press Enter to
accept these locations.

 1. Installation base ($prefix)                   : /home/tohokuaiki/pear
 2. Temporary directory for processing            : /tmp/pear/install
 3. Temporary directory for downloads             : /tmp/pear/install
 4. Binaries directory                            : /home/tohokuaiki/pear/bin
 5. PHP code directory ($php_dir)                 : /home/tohokuaiki/pear/share/pear
 6. Documentation directory                       : /home/tohokuaiki/pear/docs
 7. Data directory                                : /home/tohokuaiki/pear/data
 8. User-modifiable configuration files directory : /home/tohokuaiki/pear/cfg
 9. Public Web Files directory                    : /home/tohokuaiki/pear/www
10. System manual pages directory                 : /home/tohokuaiki/pear/man
11. Tests directory                               : /home/tohokuaiki/pear/tests
12. Name of configuration file                    : /home/tohokuaiki/.pearrc

と聞かれるけれども、「1」を選択してインストール先を変更

Installation base ($prefix) [/home/tohokuaiki/pear] : /home/tohokuaiki/test/hoge/lib/pear

で、4~11が変更される。ここで12の.pearrcも変更しておこう。

さて、おもむろにリターンを押下してインストール開始!!・・・と思いきや

1-12, 'all' or Enter to continue:
Beginning install...
XML Extension not found

あれれ?

$ php -m|grep xml
libxml

libxmlではダメなんだ。debianなので

$ sudo apt-get install -y php7.0-xml

でインストール後、再度go-pear.pharを実行する。今度は問題なく進行。途中で

Would you like to alter php.ini </etc/php/7.0/cli/php.ini>? [Y/n] : n

と聞かれるが、ひっそりとPEARを入れているのでそんなだいそれたことはするはずもなく、男は黙って「n」を押下。

すると、

I will add a workaround for this in the 'pear' command to make sure
the installer works, but please look over your php.ini or Apache
configuration to make sure /home/tohokuaiki/test/hoge/lib/pear/share/pear is in your include_path.

と「このディレクトリをinclude_pathにいれるんやで」と注意してくれた。

うーむ、/home/tohokuaiki/test/hoge/lib/pear/share/pearpearが被ってしまったな。

PEARパッケージのインストール

/home/tohokuaiki/test/hoge/lib/pear/share/pear/bin/pearPEARコマンドである。

HTTP_Request2を入れたいので

$ /home/tohokuaiki/test/hoge/lib/pear/bin/pear install HTTP_Request2

とすると、

WARNING: channel "pear.php.net" has updated its protocols, use "pear channel-update pear.php.net" to update
Cannot install, php_dir for channel "pear.php.net" is not writeable by the current user

と出る。んー、php_dirが書き込みできない…ということで、そういえば、さっきのPEAR環境設定ファイル.pearrcを指定してコマンドを打ち直す。

こんな感じ。このコマンドの長さがひっそり感を醸し出していて非常に素晴らしい。

念のためchannel-updateをした後で

$ /home/tohokuaiki/test/hoge/lib/pear/bin/pear -c /home/tohokuaiki/test/hoge/lib/pear/.pearrc channel-update pear.php.net

パッケージのインストール

$ /home/tohokuaiki/test/hoge/lib/pear/bin/pear -c /home/tohokuaiki/test/hoge/lib/pear/.pearrc install HTTP_Request2

これで無事完了。

「生きがい」という言葉は日本語だけに存在する?

この記事でwithnews.jp

「以前、テレビの取材を受けた時、ちょっと意地悪な気持ちになって『生きがいって言葉は外国にはないし、言いませんよね。生きがいがなくても人間、ハッピーに生きていけるんじゃないですか』って答えたんです」

ってあって、Google翻訳で調べてみた。

言語 翻訳 日本語に再翻訳 Bingで再翻訳
英語 reason to live 生きる理由 生きる理由
フランス語 Je souhaite vivre 私は生きたい 私は生きたい
ロシア語 Я хочу жить 私は生きたい 行きたいです
スペイン語 Deseo vivir 私は生きたい 行きたいです
イタリア語 Voglio vivere 私は生きたい 行きたいです
ドイツ語 Ich möchte leben 私は生きたい 行きたいです
中国語 我想住 私は生きたい 行きたいです
韓国語 보람 やりがい やりがいのある
タイ語 ฉันต้องการที่จะมีชีวิตอยู่ 私は生きたい 生き続けたい
トルコ語 Yaşamak istiyorum 私は生きたい 住みたい
タガログ語 Nais kong mabuhay 私は生きたい 行きたいです
インドネシア語 Aku ingin hidup 私は生きたい 行きたいです
マレー語 Saya ingin hidup 私は生きたい 行きたいです
クメール語 ខ្ញុំចង់រស់នៅ 私は生きたい -
ハワイ語 Makemake au e ola 私は生き残りたい -
ギリシャ Θέλω να ζήσω 私は生きたい 行きたいです
スワヒリ語 Napenda kuishi 私は生きたい 生きていきたいと思います
サモア Ou te fia ola 私は生きたい -
マオリ E hiahia ana ahau ki te ora 私は救われたい -
ネパール語 म बाँच्न चाहन्छु 私は生きたい -
ヒンドゥ語 मैं जीना चाहता हूँ 私は生きたい 行きたいです
ヘブライ語 אני רוצה לחיות 私は生きたい 行きたいです

機械翻訳がどこまで正しいとかは言うつもりもないし検証する気力もないが、確かにそれにぴったり該当するような言葉は無いように思える。唯一韓国が近いものを感じさせるだけだ。

ちなみに、唯一韓国語であたった「やりがい」という言葉を翻訳してみると、

言語 翻訳 日本語に再翻訳 Bingで再翻訳
英語 Rewarding 報酬 やりがい
ドイツ語 Belohnung 報酬 報酬
中国語 奖励 報酬 報酬

と、これもどうもあまりありそうにない。行為に対する代償は、精神的なものでは無く有形なものであるということ。

言葉が無いということは概念も無いか非常に希薄であるということで、「人生は何かを成し遂げるために存在する」という考え方自体が日本人独特のものであるという証左であるかもしれない。何かを為すのが目的では無く、ただ生きるために生きるということ。

この言葉には「生きがい」というものは存在しない。

今更だけど、EthnaをPHP7にしてmysqliに対応した時のメモ

昔のコードのメンテナンスです(とか言ってみる

いい加減PHPも7になってEthnaはねーんじゃないの?って感じなのですが、これがまた意外と動くので使い続けたりしています。

ただ、preg_replaceのe修正子とmysql*系の関数が無くなったのでmysqli*に対応しないといけなくて、そのメモです。ちなみに、Ethna.phpをみると

/** バージョン定義 */
define('ETHNA_VERSION', '2.5.0-preview3');

とか書かれてたりします。

やらないといけないこと

  • preg_replaceのe修正子の削除
  • mysqliの適応
  • =&を=にする。(これは一括置換とか使って)

以下コードの羅列です。

etc/*****-ini.php

<?php
     'dsn' => 'mysql://user:pass@localhost/db_name',

 ↓

<?php
     'dsn' => 'mysqli://user:pass@localhost/db_name',

DB/Ethna_DB_PEAR.php

<?php

    function getInsertId()
    {
        if ($this->isValid() == false) {
            return null;
        } else if ($this->type == 'mysql') {
            return mysql_insert_id($this->db->connection);
        } else if ($this->type == 'sqlite') {


     function isValid()
     {
          if (is_null($this->db)
             || is_resource($this->db->connection) == false) {


    function quoteIdentifier($identifier)
    {
        if (is_array($identifier)) {
            foreach (array_keys($identifier) as $key) {
                $identifier[$key] = $this->quoteIdentifier($identifier[$key]);
            }
            return $identifier;
        }
            
        switch ($this->type) {
        case 'mysql':
            $ret = '`' . $identifier . '`';
            break;

 ↓

<?php

    function getInsertId()
    {
        if ($this->isValid() == false) {
            return null;
        } else if ($this->type == 'mysql') {
            return mysql_insert_id($this->db->connection);
        } else if ($this->type == 'mysqli') {
            return mysqli_insert_id($this->db->connection);
        } else if ($this->type == 'sqlite') {

     /* mysqli_connectはresourceではなく、Objectなので */
     function isValid()
     {
          if (is_null($this->db)
             || (is_object($this->db->connection) == false && is_resource($this->db->connection) == false)) {


    function quoteIdentifier($identifier)
    {
        if (is_array($identifier)) {
            foreach (array_keys($identifier) as $key) {
                $identifier[$key] = $this->quoteIdentifier($identifier[$key]);
            }
            return $identifier;
        }
            
        switch ($this->type) {
        case 'mysql':
        case 'mysqli':
            $ret = '`' . $identifier . '`';
            break;

preg_replaceのe修正子対応

Ethna_Controller.php

まとめて書く。

<?php
         $postfix = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($action_name));
         $action_name = substr(preg_replace('/([A-Z])/e', "'_' . strtolower('\$1')", $target), 1);
         $r = preg_replace('/_(.)/e', "'/' . strtoupper('\$1')", ucfirst($action_name)) . '.' . $this->getExt('php');
         $postfix = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($forward_name));
         $r = preg_replace('/_(.)/e', "'/' . strtoupper('\$1')", ucfirst($forward_name)) . '.' . $this->getExt('php');

 ↓

<?php
         $postfix = preg_replace_callback('/_(.)/', function($m){ return strtoupper($m[1]);}, ucfirst($action_name));
         $action_name = substr(preg_replace_callback('/([A-Z])/', function($m){ return '_' . strtolower($m[1]);}, $target), 1);
         $r = preg_replace_callback('/_(.)/', function($m){ return '/' . strtoupper($m[1]); }, ucfirst($action_name)) . '.' . $this->getExt('php');
         $postfix = preg_replace_callback('/_(.)/', function($m){ return strtoupper($m[1]); }, ucfirst($forward_name));
         $r = preg_replace_callback('/_(.)/', function($m){ return '/' . strtoupper($m[1]); }, ucfirst($forward_name)). '.' . $this->getExt('php');

Plugin/Cachemanager/Ethna_Plugin_Cachemanager_Localfile.php

<?php
    function _escape($string)
    {
        return preg_replace('/([^0-9A-Za-z_])/e', "sprintf('%%%02X', ord('\$1'))", $string);
    }

 ↓

<?php
    function _escape($string)
    {
        return preg_replace('/([^0-9A-Za-z_])/', function($m){
            return sprintf('%%%02X', ord($m[1]));
        }, $string);
    }

Ethna_MailSender.php

<?php
                 $part['name'] = preg_replace('/([^\x00-\x7f]+)/e',
                     "Ethna_Util::encode_MIME('$1')", $part['name']); // XXX: rfc2231
                 $part['filename'] = preg_replace('/([^\x00-\x7f]+)/e',
                     "Ethna_Util::encode_MIME('$1')", $part['filename']);
              /* ... */
              $header[$i][] = preg_replace('/([^\x00-\x7f]+)/e', "Ethna_Util::encode_MIME('$1')", $value);

 ↓

<?php
                 if (preg_match_all('/([^\x00-\x7f]+)/', $part['name'], $m)){
                     foreach ($m[1] as &$v) $v = Ethna_Util::encode_MIME($v);
                     $part['name'] = str_replace($m[0], $m[1], $part['name']);
                 }
                 if (preg_match_all('/([^\x00-\x7f]+)/', $part['filename'], $m)){
                     foreach ($m[1] as &$v) $v = Ethna_Util::encode_MIME($v);
                     $part['filename'] = str_replace($m[0], $m[1], $part['filename']);
                 }
              /* ... */
              $header[$i][] = preg_replace_callback('/([^\x00-\x7f]+)/',function($m){ return Ethna_Util::encode_MIME($m[1]); }, $value);

Ethna_AppObject.php

<?php
         $table = preg_replace('/^([A-Z])/e', "strtolower('\$1')", $table);
         $table = preg_replace('/([A-Z])/e', "'_' . strtolower('\$1')", $table);

 ↓

<?php
         if (preg_match_all('/^([A-Z])/', $table, $m)){
             foreach ($m[1] as &$v) $v = strtolower($v);
             $table = str_replace($m[0], $m[1], $table);
         }
         if (preg_match_all('/([A-Z])/', $table, $m)){
             foreach ($m[1] as &$v) $v = "_" . strtolower($v);
             $table = str_replace($m[0], $m[1], $table);
         }

=& newをつぶす

find lib app -name "*php"|xargs -I{} sed -i -e "s/ = &new/ = new/" {}
find lib app -name "*php"|xargs -I{} sed -i -e "s/ =& new/ = new/" {}

またdebianのvsftpdでハマったのでメモ

環境

uname -a
Linux www 4.9.0-3-amd64 #1 SMP Debian 4.9.30-2+deb9u2 (2017-06-26) x86_64 GNU/Linux

いつものように、chrootしてバーチャルユーザーでのログイン。

症状1.

vsftpでつなごうとするとConnection Refusedされる。

ローカルからFTPコマンドでたたいても同じ。

$ ftp
ftp> open localhost
ftp: connect to address ::1: Connection refused
Trying 127.0.0.1...
ftp: connect: Connection refused

チェック項目

こんな感じで調べて何とかなった。

modprobeでモジュールチェック

# lsmod|grep ftp
nf_nat_ftp             16384  0
nf_nat                 28672  1 nf_nat_ftp
nf_conntrack_ftp       20480  1 nf_nat_ftp
nf_conntrack          114688  5 nf_conntrack_ftp,nf_conntrack_ipv4,nf_nat_ftp,xt_conntrack,nf_nat

これがなかったら以下を入れておく。

# modprobe nf_conntrack_ftp
# modprobe nf_nat_ftp

バーチャルユーザーのshell

とりあえずバーチャルユーザーの割り当てにはftp_userというユーザーを作ってたんだけど、これのshellが/usr/sbin/nologinだと動作しない。

vsftpd.conf

この2つは両立させられないらしいので、ipv6は使わないようにする。

listen=YES
listen_ipv6=NO

ホームディレクトリを555パーミッションに設定

こんな感じでバーチャルユーザーを設定していると、

# more /etc/vsftpd.d/vsftpd_user_conf/vftpuser
guest_username=vftpuser
local_root=/home/example

/home/exampleのパーミッションを555にしなければならない。

が、最近のVSFTPDだと

allow_writeable_chroot=YES

で行ける。

パッシブモードで引っかかる

このあたりでお勉強

FTPのアクティブモードとパッシブモード + vsftpdでの設定方法|A Day In The Boy's Life

centos - How to configure vsftpd to work with passive mode - Server Fault

どうもポートを開放しないとダメっぽい。あれー、今まで動いてたのになぁ・・・。

ということで、vsftpd.confに以下を記述。

pasv_enable=YES
pasv_min_port=61050
pasv_max_port=61100

で、iptablesをこんな感じで。192.168.xxx.xxxは自ホスト。

iptables -A INPUT -p tcp -s 0.0.0.0/0 -d 192.168.xxx.xxx --dport 61050:61100 -j ACCEPT
iptables -A OUTPUT -p tcp -s 192.168.xxx.xxx --sport 61050:61100 -d 0.0.0.0/0 -j ACCEPT

毎回何かしら引っかかるね。。。

PHPでeBayのAPIを使う

結論から言うと、APIのReferenceがあるけどそんなのは見なくてPHPSDKがあるからそれを使ったらすぐだった。

とにかく、SandboxとProductionの両方を行き来するのでどっちがどっちかわからなくなるし、いつの間にかアカウントできてたのでこの2つがリンクするというのはどういう風なんだろう?メールアドレスが同じものをSandboxとProductionの両方で使って登録すればいいのかしら?

わかんなくなったら、My eBayにそれぞれログインする。 * http://my.ebay.com:tilte=Production用 My eBay * Sandbox用 My eBay

eBay developerアカウントを作る

Sandbox用とproduction用の2つ作成。

どちらから作り始めてもいいのだけど、sandbox用は「testuser_」がPrefixになる。

正直、ごちゃごちゃとやってたら2個できたし、その2個がリンクしてるのはどうやって作るのかはわからない。

こっちに書いてあった、テスト用Sandboxユーザーの登録方法

eBay Features - Testing in the Sandbox

  • Set up an email account for each Sandbox test user. A unique email is required for each test user you create.
  • On the eBay Developers Program home page, either create a developer’s account by clicking the Register link or login by clicking the eBay Developer Login button.
  • Sign in as a developer, using your eBay Developers Program username and password.
  • Go to the eBay Sandbox User Registration Tool page.
  • Create your test user by filling in the Username and Password fields. You can leave the other fields as is. Click the Create User button.

アプリケーションを登録してキーを取得

Applicationの名前を決めて、そのキーを取得 f:id:tohokuaiki:20170905183629p:plain

これも、SandboxとProductionの両方。

色々と求められるかもしれないけど、とりあえず携帯電話のSMSがあればなんとか突破できる。

Authトークンを取得

「Auth'n'Aut」と「hOAuth (new security)」と2つあるけど2つとも取得しておく。

f:id:tohokuaiki:20170905183906p:plain

この時、これでもかというくらいにログインをさせられるけど我慢する。

Return URLを登録

Authした時に返却されるURLとかプライバシーポリシーなんかのURLを登録しておく。別にeBayが後でクロールしてチェックとかはしないので適当なURLを入れておけばOK。

f:id:tohokuaiki:20170905184326p:plain

これも、当然SandboxとProductionの両方。

PHP eBay API SDKを取得

素晴らしいサイトから取得する。 devbay.net

面倒なので、githubから直接。
GitHub - davidtsadler/ebay-sdk-examples: Several examples of using the eBay SDK for PHP

composer.jsonがあるので、例によってcomposer installする。

ebay-sdk-examples/configuration.php の設定

大体見ればわかると思う。

ruNameというのが引っかかったのだけど、これは、Return URL Nameということで、先ほど登録してReturn URLの名称なのである。自分の場合、上のキャプチャ画面だとTakashi_ITOH-TakashiI-Junoef-fbnbhijtpとかいうのがそれにあたる。

sellerアカウントを設定

とりあえずこれで使えることは使える。Select系のAPIはProductionを使用する。登録系のAPIはSandboxを使用する。

登録系のAPIを使うにはSellerアカウントにしないといけない。

そのためのセットアップがここにある。Getting started selling on eBay

すると、My eBayのアカウントページで「Seller Account」というのが出てくるらしい。

f:id:tohokuaiki:20170905190806p:plain

で、これを当然のようにSandboxとProductionの両方で行う。

が、SandboxのSellerアカウントが設定できない・・・

上述のは、Productionの設定しか書いてなかった。いや、むしろテストするだけならSandboxの方だけで構わないのに、Productionの方だけSellerアカウントができてしまった。

Sandboxは登録しなくてもSellerテストできるんじゃん?って思ってSDKのサンプル商品登録を試してみたら

Error: You need to create a seller's account.
Before you can list this item we need some additional information to create a seller's account.

って出た。デスヨネー。

仕方ないのでSandboxのMy eBayに行くと How to Sell Items on eBay などと書いてあり、

  • Sign up for PayPal (optional)
  • Fill out the Sell Your Item form

とある。optionalとあるPaypalの方は後回しにして、「go to the Sell Your Item form.」ってリンクをクリックするとリンク切れ。左のメニューにSeller Dashboardというのもあるのでそっちにヒントあるかな?と思ってクリックしたらリンク切れ。切れそう。

My eBay Viewsをシラミ潰す。

とにかくここに「Seller Account」というのが出ればいいのである。

f:id:tohokuaiki:20170905192629p:plain

しかし、PaypalにLinkさせればいいのかと思いきや、昔作って使えてたPaypalのアカウントがペンディングになっててダメだったり、新しくPaypalのSandboxユーザーで作ればいいんじゃないかと

f:id:tohokuaiki:20170906115646p:plain

ここのリンクから作ろうとしたら、PaypalのSandboxユーザー登録で電話番号がアメリカ形式じゃないとかZIPコードがお前の入力した住所と一致してないとかアメリカの電話番号・郵便番号の形式や実在するものを調べて入力したけどダメ。およそSandboxっぽくない。もちろん国をUSから変更することはできない。

困り果ててもう一度検索

もしかすると、作ったSandboxユーザーを「Sellerにする」という発想が間違っているのではないか?・・・すると、こんなページが見つかった。

eBay Features - Testing in the Sandbox

The process of registering a test user is different than that for registering a real user in the Production environment. After you register a Sandbox test user, you can use it to buy and sell test items in the eBay Sandbox.

買う用と売る用の2つのテストアカウントが必要ですよと。

なんだそんなの・・・売る用(Seller)アカウントが作れないから困ってるんだっていうの・・・と思いつつ、この画面のここからもう一つ作ってみる。

f:id:tohokuaiki:20170906120222p:plain

そして、新しいSandboxユーザーでログイン・・・・。

・・・なんかSellerアカウントになってるね。

f:id:tohokuaiki:20170906120524p:plain

で、Tokenを2つ発行して、configuration.phpに設定・・・

vagrant@debian:~/work/ebay/ebay-sdk-examples$ php trading/03-add-auction-item.php
The item was listed to the eBay Sandbox with the Item number 110222380931

おぉっ!!!できてる!!!ホンマ、なんつー、落とし穴やねん。。。