2021/07/20

今回はピュアなPHPで実装する必要があったので 「php-markdown」を使ったMarkDown 処理を試してみました。

php-markdown

Composer でインストール

Composermichelf/php-markdown をインストールします。

% composer require michelf/php-markdown

コードブロックの対応は MarkdownExtra を使う

単純にマークダウンを使うときは、Markdown で大丈夫ですが、コードブロックの pre, code タグに対応していません。

use Michelf\Markdown;

コードブロックに対応するには、MarkdownExtra を利用します。

use Michelf\MarkdownExtra;

MarkDown を HTML に変換する

MarkDown を HTML に変換するのはこれだけです。

$markdown = new MarkdownExtra();
$content = $markdown->transform($content);

ただ、 prism.js にも対応させたいので code_class_prefixlanguage- をつけておきます。関数とかにまとめるとこんな感じです。

function markdownToHtml($content){
    $markdown = new MarkdownExtra();
    $markdown->code_class_prefix = 'language-';
    return $markdown->transform($content);
}

//マークダウン文章
$markdown = "
    ``` php
    function hoge($value)
    {
        return $value;
    }
    ```
";

//HTMLに変換
$html = markdownToHtml($markdown);

MarkdownExtra の pre, code 処理

これはマニュアルに載ってないので MarkdownExtra のソースコードを調べてみました。 $matches は文章に正規表現をかけた配列で、クラス名は index=2 にマッチします。あとは、 $code_class_prefix をくっつけてますね。

        protected function _doFencedCodeBlocks_callback($matches) {
        $classname =& $matches[2];
        $attrs     =& $matches[3];
        $codeblock = $matches[4];

        if ($this->code_block_content_func) {
            $codeblock = call_user_func($this->code_block_content_func, $codeblock, $classname);
        } else {
            $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
        }

        $codeblock = preg_replace_callback('/^\n+/',
            array($this, '_doFencedCodeBlocks_newlines'), $codeblock);

        $classes = array();
        if ($classname !== "") {
            if ($classname[0] === '.') {
                $classname = substr($classname, 1);
            }
            $classes[] = $this->code_class_prefix . $classname;
        }
        $attr_str = $this->doExtraAttributes($this->code_attr_on_pre ? "pre" : "code", $attrs, null, $classes);
        $pre_attr_str  = $this->code_attr_on_pre ? $attr_str : '';
        $code_attr_str = $this->code_attr_on_pre ? '' : $attr_str;
        $codeblock  = "<pre$pre_attr_str><code$code_attr_str>$codeblock</code></pre>";

        return "\n\n".$this->hashBlock($codeblock)."\n\n";
    }

  2021/02/24

EC-CUBE4 で Gmail の smtp の設定方法は、.env の MAILER_URL に記述します。

前提として、Googleセキュリティでの2段階認証が必要になります。

  • smtp: smtp.gmail.com
  • port: 465
  • encryption: ssl
  • auth_mode: login
  • username: Gmail アカウント(Gmail アドレス)
  • password: Google セキュリティの2段階認証で作成したパスワード(Gmail アカウントのパスワードではありません)

EC-CUBE の.env

EC-CUBE4 から Swift Mailer を利用しますが、smtpプロトコルの URLをパラメータ方式で設定します。


MAILER_URL=smtp://smtp.gmail.com:465?encryption=ssl&auth_mode=login&username=xxxxx@gmail.com&password=xxxxxx

  2020/10/24

Composer でインストールする時にメモリ不足のエラーがでることがあります。

$ composer require "laravelcollective/html"
....
Fatal error: Allowed memory size of 1610612736 bytes exhausted (tried to allocate 4096 bytes) in phar:///usr/local/Cellar/composer/1.10.10/bin/composer/src/Composer/DependencyResolver/Solver.php on line 223

Check https://getcomposer.org/doc/articles/troubleshooting.md#memory-limit-errors for more info on how to handle out of memory errors.MBP:

PHP のメモリ確認

まず現状の PHP のメモリ上限を確認します。


$ php -i | grep memory_limit
memory_limit => 128M => 128M

メモリが 128M になっています。

php.ini ファイルの確認

PHP 設定ファイル php.ini で設定変更するためファイルパスを調べます。


$ php --ini
Configuration File (php.ini) Path: /usr/local/etc/php/7.4
Loaded Configuration File:         /usr/local/etc/php/7.4/php.ini
Scan for additional .ini files in: /usr/local/etc/php/7.4/conf.d
Additional .ini files parsed:      /usr/local/etc/php/7.4/conf.d/ext-opcache.ini

今回の場合「/usr/local/etc/php/7.4/php.ini」が設定ファイルです。

php.ini で memory_limit を設定

php.ini ファイルを修正します


$ vi /usr/local/etc/php/7.4/php.ini

メモリ上限の設定 memory_limit を無制限(-1)に設定します


;memory_limit = 128M
memory_limit = -1

設定が変更されたか確認します。


$ php -i | grep memory_limit
memory_limit => -1 => -1

Composer コマンドのメモリ指定 

Composer コマンド実行時にメモリ制限を無制限にすることもです。以下は、Composer のアップデート処理で PHP のメモリ上限をなしにした実行です。


$ php -d memory_limit=-1 /usr/local/bin/composer update

  2020/03/02

composer update したところ、ext-dom がないから PHPUnitが入れられないようです。


$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - phpunit/phpunit 8.5.x-dev requires ext-dom * -> the requested PHP extension dom is missing from your system.
...

php-xml をインストール


# aptitude update
# aptitude install php-xml

再度 composer update する

今度は、インストールが進み、vendor もインストールされた。


$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 87 installs, 0 updates, 0 removals
As there is no 'unzip' command installed zip files are being unpacked using the PHP zip extension.
This may cause invalid reports of corrupted archives. Besides, any UNIX permissions (e.g. executable) defined in the archives will be lost.
Installing 'unzip' may remediate them.
  - Installing symfony/polyfill-ctype (v1.14.0): Loading from cache
...

  2020/02/08

DIについては、DI(依存性注入) を参照

DIコンテナは、DIのインスタンス生成を、別のファイルでコンテナ化して解決しようという設計パターンです。

共通クラスを用意

まず、共通で使う Animalクラスを用意します。
手っ取り早くファイル分割せず Animal.php にクラス(Dog、Cat)を記述しました。


interface Animal {
    public function bow();
}

class Dog implements Animal {
    public function bow() {
        echo 'wan! wan!'.PHP_EOL;
    }
}

class Cat implements Animal {
    public function bow() {
        echo 'nya-! nya-!'.PHP_EOL;
    }
}

DIでない例

下記のサンプルはコンストラクタ内で Dog を生成して鳴きます。


class AnimalConsole {
    protected $dog;

    public function __construct() {
        $this->dog = new Dog();
    }

    public function bow() {
        $this->dog->bow();
    }
}

$animal_console = new AnimalConsole();
$animal_console->bow();

この場合、コンストラクタで new Dog() するため、Dogが実装できるまで AnimalConsole が実装できません。

DI(?)の場合

コンストラクタの引数に、Dog、Cat インスタンスを注入します(コンストラクタインジェクション)
他の記事をみているとこれで「DI」となってますが、まだ Dog に依存しているため Cat に修正したい場合に手間がかかります。


require_once 'Animal.php';

class AnimalConsole {
    protected $dog;

    public function __construct(Dog $dog) {
        $this->dog = $dog;
    }

    public function bow() {
        $this->dog->bow();
    }
}

$animal_console = new AnimalConsole(new Dog());
$animal_console->bow();

インターフェイス(モック)を引数にしてみる

今度は Dog、Cat 両方扱えるように Amimal を引数とします。


require_once 'Animal.php';

class AnimalConsole {
    protected $animal;

    public function __construct(Amimal $animal) {
        $this->animal = $animal;
    }

    public function bow() {
        $this->animal->bow();
    }
}

$animal_console1 = new AnimalConsole(new Dog());
$animal_console1->bow();

$animal_console2 = new AnimalConsole(new Cat());
$animal_console2->bow();

これで、Dog、Cat どちらでも注入できるようになりました。

pimpleでDIコンテナを作成する

インスタンスを直接渡すのではなく、コンテナ(箱)内でインスタンスを作成して処理するのが、DIコンテナです。

今回は、composerのContainerライブラリ「pimple」を利用しています。

Pimpleインストール


$ composer require pimple/pimple ~3.0

PimpleによるDIコンテナ

下記の場合、Dog、Cat のインスタンスをコンテナ化しています。

また、$container['animal'] では、インスタンスを簡単に切り替えることができます。


require_once 'Animal.php';
require_once __DIR__.'/../vendor/autoload.php';

use Pimple\Container;

class AnimalConsole {
    protected $animal;

    public function __construct(
        Animal $animal
        ) {
        $this->animal = $animal;
    }

    public function bow() {
        $this->animal->bow();
    }
}

$container = new Container();

$container['dog'] = function($c) {
    return new Dog();
};

$container['cat'] = function($c) {
    return new Cat();
};

$container['animal'] = function($c) {
    return $c['dog'];
};

$container['animalConsole'] = function ($c) {
    return new AnimalConsole($c['animal']);
};

$container['animalConsole']->bow();

Container の部分はファイル分離する必要はあります。

  2020/02/06

freee API は 開発者向けにOSS として公式公開されています。

https://developer.freee.co.jp/

 

ここでは、リファレンスを利用して認可コード・アクセストークン・API確認をしてみる。

実際の開発は各言語やSDKを使ってコーディングが必要だが、PHPに関しては、freee SDKを Laravel で使ってみる でやってみた。

開発者アカウント登録と環境・アプリ作成

まず、freeeアカウントを作成(一般ユーザアカウント)する

開発用テスト環境作成

次に開発ユーザでログインし、開発用テスト環境の作成する。

テスト環境の事業所を選択

アプリ追加

 アプリ追加画面でアプリを追加すると、Client ID, Client secret が発行される

作成したアプリは、アプリ管理 で管理する

freee API のドキュメント

API を試してみる

認可コード発行

「Webアプリ認証用URL」でブラウザでアクセスし、許可すると「認可コード」が発行される
※アクセストークンではない

アクセストークン発行

https://accounts.secure.freee.co.jp/public_api/authorize?client_id={client_id}&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=token 

上記のURLに freee アプリで発行された Client ID を入れてブラウザでリクエストする

事業所取得

https://developer.freee.co.jp/docs/accounting/reference#/Companies/get_companies

鍵マークをクリック

value に アクセストークンを入力して [Authorize]し、成功したら[Close]

[Try it out] をクリックし [Execute] するとAPIが実行される

事業所一覧取得API(companies)の場合

curl


curl -X GET "https://api.freee.co.jp/api/1/companies" -H "accept: application/json" -H "Authorization: Bearer {Client ID}"

Request Body


https://api.freee.co.jp/api/1/companies

Request URI


{
  "companies": [
    {
      "id": xxxxxxx,
      "name": "",
      "name_kana": "",
      "display_name": "個人事業主名",
      "role": "admin"
    },
    {
      "id": xxxxxxx,
      "name": null,
      "name_kana": null,
      "display_name": "個人事業主スタータープラン: 開発用テスト環境",
      "role": "admin"
    }
  ]
}

  2020/01/12

Composer 公式のインストール

https://getcomposer.org/download/

$ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
$ php -r "if (hash_file('sha384', 'composer-setup.php') === 'baf1608c33254d00611ac1705c1d9958c817a1a33bce370c0595974b342601bd80b92a3f46067da89e3b06bff421f182') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
$ php composer-setup.php
$ php -r "unlink('composer-setup.php');"
$ sudo mv composer.phar /usr/local/bin/composer

getcomposer.org のPHPインストーラを利用する

ComposerインストールようのPHPファイル https://getcomposer.org/installer を利用して /usr/local/bin/ にcomposer をインストール

$ curl -s https://getcomposer.org/installer | php && sudo mv -v composer.phar /usr/local/bin/composer

Composer バージョン確認

$ composer --version
Composer version 1.9.1 2019-11-01 17:20:17

Composer アップデート

$ composer self-update

  2019/12/30

DIとは

DI(Dependency injection) は依存性の注入の意味です。

ここで言う「依存性」は、オブジェクト思考でいうと大まかに「クラスファイル」と考えて良いかと。

そしてそのクラスが特定の定数、変数、インスタンスに依存しまい、単体テストに支障がでている状態です。

class Dog {
    public function isBow() {
        $person = new Person();
        return ($person->action() ==  'walk');
    }
}
class TestDog {
    public function testBow() {
        $dog = new Dog();
        $this->assertTrue($dog->isBow());
    }
}

上記だと、Dogクラス内にPersonクラスに依存してしまってます。 「$person->action() == 'walk'」の実装が変わってしまうと、assertTrue() した結果は、Personクラスが変更があった場合に変わってしまいます。

解決方法としては、Dogクラスの動作させるメソッドでインスタンスを作成せずに、コンストラクタやセッターに、Personを入れて(注入)して解決します。

class Dog {
    protected $person;
   
    public function __construct(Person $person) {
        $this->person = $person;
    }

    public function isBow() {
        return ($this->person->action() == 'walk');
    }
}
class TestDog {
    public function testBow() {
        $person = new Person();
        $person->expects($this->any())
            ->method('action')
            ->will($this->returnValue('walk'));
        $dog = new Dog($person);
        $this->assertTrue($dog->isBow());
    }
}

  2019/05/15

UFJ が API を虎視眈々と開発していた。

カブドットコムのAPIも使えたりと結構楽しそう、というか近々実用化されそうな予感がします。

カブドットコムのAPI(kabu.com API)は本番環境で利用できるとのことだが、
法人契約が必要なのと当然ながら審査が必要です。

開発用API登録

UFJ API

API種別

2019/05/15現在、個人口座、法人口座、振込申請、総合振込申請、給与賞与振込申請、特別徴収地方税のAPIが用意されている。

UFJ API

API Client Secretの発行

当然ながらAPIを利用するには、Client Secret の発行が必要となる。

UFJ API

APIリファレンス

各サービス毎にリファレンスは用意されている。

cURL,Ruby,Python,PHP,Java,Node,Go,Swift のサンプルが記載されており、
結構本気度が伺えられる。 また、レスポンスは基本 json のようだ。

UFJ API

ただ本番利用の場合は、金融業界なので審査が厳しいと予想される。

ライブラリ(PHP)

使いやすいように、Github にクラスライブラリを作成してました。

https://github.com/yoo16/ufj_api (2019/05/15現在アカウント情報取得のみ)

また、検証用データが用意されていて、Account ID一覧は以下の通り


001001110001 002001110002 325001110003 135011110005 118011110008 
329011110009 002021110013 002022220003 325022220004 909022220013 
002022220014 002023330003 325023330004 480023330005 777023330008 
118023330009 427383330012 909383330013 002383330014 002283330016

実行結果


$ php get_account.php 002023330003 

{"branchNo":"002","branchName":"丸の内","accountTypeCode":"02",
"accountTypeDetailCode":"00099",
"accountTypeName":"定期","accountNo":"3330003",
"accountName":null,"accountNameKana":null,
"balance":100000,"withdrawableAmount":null,
"currencyCode":"JPY"
,"foreignCurrencyBalance":null,
"yenEquivalent":null,"exchangeRate":null,
"totalMarketValue":null,
"totalUnrealizedProfitAndLoss":null,
"mutualFundAccountType":null,"fundBaseDate":null}

  2019/04/29

PHP7.3 で break と continue の取り扱いが変更になった影響で、composer install がエラーになる場合、

  • PHP7.2にさげる
  • composer のバージョンをあげる

<

ul>

$ composer global require "laravel/installer"
Changed current directory to /home/yoo/.config/composer
Using version ^2.0 for laravel/installer
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)

Installation failed, deleting ./composer.json.
                                                                                           
  [ErrorException]                                                                         
  "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"?  
                                                                                           
require [--dev] [--prefer-source] [--prefer-dist] [--no-progress] [--no-update] [--no-scripts] [--update-no-dev] [--update-with-dependencies] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [--sort-packages] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--] []...

特に初期設定で composer のバージョンが低い場合は注意が必要 (composer self-udpate がないなど) composer installができなくなった時の解決法(PHP7.3)

PHP7.2 に変更

$ sudo update-alternatives --config php
  選択肢    パス           優先度  状態
------------------------------------------------------------
*0            /usr/bin/php7.3   73        自動モード
  1            /usr/bin/php5     50        手動モード
  2            /usr/bin/php7.0   70        手動モード
  3            /usr/bin/php7.2   72        手動モード
  4            /usr/bin/php7.3   73        手動モード

composerの再インストール(self-udpateなど利用できない場合)

composer-setup.php をダウンロード・実行する

$ curl -sS https://getcomposer.org/installer | php
$ sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer
$ composer -V
Composer version 1.8.5 2019-04-09 17:46:47

2019/12/09追記 一発でインストールする

$ curl -s https://getcomposer.org/installer | php && sudo mv -v composer.phar /usr/local/bin/composer
<< Top < Prev Next > Last >>