今回はピュアなPHPで実装する必要があったので 「php-markdown」を使ったMarkDown 処理を試してみました。
Composer で michelf/php-markdown をインストールします。
% composer require michelf/php-markdown
単純にマークダウンを使うときは、Markdown で大丈夫ですが、コードブロックの pre, code タグに対応していません。
use Michelf\Markdown;
コードブロックに対応するには、MarkdownExtra を利用します。
use Michelf\MarkdownExtra;
MarkDown を HTML に変換するのはこれだけです。
$markdown = new MarkdownExtra();
$content = $markdown->transform($content);
ただ、 prism.js にも対応させたいので code_class_prefix に language- をつけておきます。関数とかにまとめるとこんな感じです。
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 のソースコードを調べてみました。 $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";
}
EC-CUBE4 で Gmail の smtp の設定方法は、.env の MAILER_URL に記述します。
前提として、Googleセキュリティでの2段階認証が必要になります。
EC-CUBE4 から Swift Mailer を利用しますが、smtpプロトコルの URLをパラメータ方式で設定します。
MAILER_URL=smtp://smtp.gmail.com:465?encryption=ssl&auth_mode=login&username=xxxxx@gmail.com&password=xxxxxx
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 -i | grep memory_limit
memory_limit => 128M => 128M
メモリが 128M になっています。
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 ファイルを修正します
$ 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 のアップデート処理で PHP のメモリ上限をなしにした実行です。
$ php -d memory_limit=-1 /usr/local/bin/composer update
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.
...
# aptitude update
# aptitude install php-xml
今度は、インストールが進み、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
...
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;
}
}
下記のサンプルはコンストラクタ内で 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 が実装できません。
コンストラクタの引数に、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 どちらでも注入できるようになりました。
インスタンスを直接渡すのではなく、コンテナ(箱)内でインスタンスを作成して処理するのが、DIコンテナです。
今回は、composerのContainerライブラリ「pimple」を利用しています。
$ composer require pimple/pimple ~3.0
下記の場合、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 の部分はファイル分離する必要はあります。
freee API は 開発者向けにOSS として公式公開されています。
https://developer.freee.co.jp/
ここでは、リファレンスを利用して認可コード・アクセストークン・API確認をしてみる。
実際の開発は各言語やSDKを使ってコーディングが必要だが、PHPに関しては、freee SDKを Laravel で使ってみる でやってみた。
まず、freeeアカウントを作成(一般ユーザアカウント)する
次に開発ユーザでログインし、開発用テスト環境の作成する。
アプリ追加画面でアプリを追加すると、Client ID, Client secret が発行される
作成したアプリは、アプリ管理 で管理する
「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が実行される
curl -X GET "https://api.freee.co.jp/api/1/companies" -H "accept: application/json" -H "Authorization: Bearer {Client ID}"
https://api.freee.co.jp/api/1/companies
{
"companies": [
{
"id": xxxxxxx,
"name": "",
"name_kana": "",
"display_name": "個人事業主名",
"role": "admin"
},
{
"id": xxxxxxx,
"name": null,
"name_kana": null,
"display_name": "個人事業主スタータープラン: 開発用テスト環境",
"role": "admin"
}
]
}
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
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 --version
Composer version 1.9.1 2019-11-01 17:20:17
$ composer self-update
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());
}
}
UFJ が API を虎視眈々と開発していた。
カブドットコムのAPIも使えたりと結構楽しそう、というか近々実用化されそうな予感がします。
カブドットコムのAPI(kabu.com API)は本番環境で利用できるとのことだが、
法人契約が必要なのと当然ながら審査が必要です。
2019/05/15現在、個人口座、法人口座、振込申請、総合振込申請、給与賞与振込申請、特別徴収地方税のAPIが用意されている。
当然ながらAPIを利用するには、Client Secret の発行が必要となる。
各サービス毎にリファレンスは用意されている。
cURL,Ruby,Python,PHP,Java,Node,Go,Swift のサンプルが記載されており、
結構本気度が伺えられる。 また、レスポンスは基本 json のようだ。
ただ本番利用の場合は、金融業界なので審査が厳しいと予想される。
使いやすいように、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}
PHP7.3 で break と continue の取り扱いが変更になった影響で、composer install がエラーになる場合、
<
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)
$ 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-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