技術的な話題 に関する投稿を表示しています

Composer は何者か。あるいは install と update の違い。そしてオートロードの仕組み。

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

たいとるそのまま。

Composer 使って Packagist から ライブラリを入れられるけど結局何者なんだ、 install と update の違いはなんだ、つーかオートロードってどうなってんねん、などなどがよくわからなかったのでドキュメントとかソースを見た。

 

Composer とは?

Introduction - Composer

このあたりを、見ると大体解決する。

Composer "Dependency Manager for PHP"
→ PHP向けの依存関係管理システム

Ruby における Bundler や Node.js における npm のように、 PHP に対しての Composer 。

Composer 自体も PHP で書かれていて、PHP 5.3.2 以降の環境ならうまく動いてくれる。
場合によっては、コンパイルオプションの指定やモジュールの追加、コンフィグの問題などが発生するが、 Composer が判別し、警告を出してくれるのでその時に対応すれば良い。

 

依存関係管理?

作っていく PHP アプリケーション(あるいは PHP ライブラリ)が、ほかのライブラリに「依存」している場合、依存しているライブラリもセットにしないと動作しない。

仮にそのライブラリがまた別のライブラリに「依存」していたら…?
あるいは、ライブラリ A と別のライブラリ B が、ある同じライブラリ C に依存しているけど、 C と C' のように違うバージョンが対象だったら…?

などなどの非常にやっかいなライブラリ依存関係を、簡単な記述で管理できるようにしたものが依存関係管理システム。

PHP なら PEAR がある。が、今この時代では Composer のほうがよく使われている…はず。

 

Composer インストール

composerのインストールは非常に簡単。

$ curl -sS https://getcomposer.org/installer | php

この場合はカレントディレクトリに comopser.phar というファイルが作られ、これがComposerの本体になる。

どのディレクトリからでも実行できるように、どのユーザでも実行できるようにするためにはシステムにインストールする必要がある。

その際には、以下のコマンドで。

$ sudo mv composer.phar /usr/local/bin/composer
$ sudo chown root:root /usr/local/bin/composer
$ sudo chmod +x /usr/local/bin/composer

 

Composer がすること

  • composer コマンドの提供
  • 依存するライブラリについて
  • 依存関係の解決(ダウンロード&展開)
  • ライブラリ検索
  • 依存関係の追加
  • 依存関係の除去
  • オートロード用ファイルの提供

 

composer コマンドの提供

Composer をインストールすると composer というコマンドが利用できる。

※リネームしていない場合 composer.phar が実行コマンド。
実行権限が無い場合は php composer.phar XXXX のように php コマンドへの入力として実行する必要あり。

composer コマンドには、おおざっぱに以下の機能がある。

  • init
    • カレントディレクトに新しく composer.json を生成する
  • require
    • 依存関係を追加する
  • remove
    • 依存関係を削除する
  • install
    • composer.json に基づいて依存関係を解決する
    • composer.lock というファイルが存在する場合は、それに従う。
  • update
    • composer.json に基づいて依存関係を再度解決し composer.lock ファイルを更新する
  • dump-autoload
    • オートロード用ファイルを生成する
  • search
    • ライブラリを Packagist から探す
  • self-update
    • composer コマンド自体を更新する

他にも細かいところがあるので、気になったらドキュメントへ。
Command-line interface / Commands - Composer

 

composer install と composer update の違い

install

  • 7文字
  • composer.lock があればそれに従ってライブラリを導入する
  • composer.json に従ってライブラリを導入する

update

  • 6文字
  • composer.lock があっても composer.json に従ってライブラリを導入する

composer.lock は実際にインストールされているライブラリ、バージョンが記載されている。
composer.json には、このアプリケーション(ライブラリ)が一体どのライブラリ、どのバージョンに依存しているかを記載する。そのときライブラリのバージョンアップを形容できる書き方がある。

 

composer.json におけるバージョン指定の方法

詳しくはドキュメントにまとまってる。
Versions and constraints - Composer

ざっくりまとめると。

  • 固定値
    • 1.0.2
  • 範囲指定
    • > >= < <= != ||
    • 記号は書いたそのままの意味、|| は OR 。スペースで AND 。
    • >=1.0
      • 1.0 以上
    • >=1.0 <2.0
      • 1.0 以上 かつ 2.0 未満
    • >=1.0 <1.1 || >=1.2
      • (1.0 以上 かつ 1.1 未満)または 1.2 以上
  • ハイフンの範囲指定
    • 1.0 - 2.0
      • >=1.0.0 <2.1 と等価
      • 1.0 以上 かつ 2.1 未満
  • ワイルドカード
    • 1.0.*
      • >= 1.0 <1.1
      • 1.0 以上 かつ 1.1 未満
  • チルダ
    • 指定した一番小さいバージョンの変化を形容する
    • ~1.2
      • >= 1.2 <2.0
    • ~1.2.3
      • >= 1.2.3 <1.3
  • ハット
    • セマンティックバージョニングに従う = メジャーバージョンを上げない
    • ただし 1.0 未満はマイナーバージョンに合わせる
    • ^1.2.3
      • >=1.2.3 <2.0.0
    • ^0.3
      • >=0.3.0 <0.4.0

チルダ + マイナーバージョン指定にしておけば、大きな変更に殺されることはなさそう。

 

Composer の提供するオートローダーとは

composer dump-autoload を実行すると、 composer.json の内容にもとづいてオートロード用のファイルが作られる。ファイルは複数あり、以下の場所で確認できる。

  • vendor/autoload.php
  • vendor/composer/*

これらのファイルは次のような仕組みで成り立っている。ソースにコメントをつけて流れを見ていく。

<?php
// vendor/composer/autoload_real.php を読み込み、そちらに処理が移る。

require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitaf2b1a382e2c643bceff8e5e7a5cce1d::getLoader();

vendor/composer/autoload_real.php

<?php
// 余談だけどこのハッシュ値っぽいものは指定できる。
// composoer config に autoloader-suffix があればそれで、なければ md5(uniqid('', true)) が使われる。
//
// composer.json に書くなら config > autoloader-suffix になるようにする。
// composer config autoloader-suffix HogeeeHugaaa でも可。
class ComposerAutoloaderInitaf2b1a382e2c643bceff8e5e7a5cce1d
{
    // ClassLoader インスタンス
    private static $loader;

    // spl_autoload_register によって利用される ClassLoader を読み込む
    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        // ClassLoader の読み込み
        spl_autoload_register(array('ComposerAutoloaderInitaf2b1a382e2c643bceff8e5e7a5cce1d', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
        spl_autoload_unregister(array('ComposerAutoloaderInitaf2b1a382e2c643bceff8e5e7a5cce1d', 'loadClassLoader'));

        // PHP で、かつ Zend Guard Loader の拡張が有効なら autoload_static.php を利用する
        // 余談)Zned Guard Loader は Zned Optimizer によって作られたエンコードされた PHP ファイルを実行するためのもの
        // http://www.zend.com/en/products/guard/zend-optimizer-zend-loader
        $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
        if ($useStaticLoader) {
            require_once __DIR__ . '/autoload_static.php';

            call_user_func(\Composer\Autoload\ComposerStaticInitaf2b1a382e2c643bceff8e5e7a5cce1d::getInitializer($loader));
        } else {
            // 条件に該当しなかった場合は、各ファイルを個別に読み込む

            // 名前空間の定義がされたものを読み込み
            $map = require __DIR__ . '/autoload_namespaces.php';
            foreach ($map as $namespace => $path) {
                $loader->set($namespace, $path);
            }

            // PSR-4 形式で定義されたものを読み込み
            $map = require __DIR__ . '/autoload_psr4.php';
            foreach ($map as $namespace => $path) {
                $loader->setPsr4($namespace, $path);
            }

            // 直にクラスが指定されているものを読み込み
            $classMap = require __DIR__ . '/autoload_classmap.php';
            if ($classMap) {
                $loader->addClassMap($classMap);
            }
        }

        // 読み込んだファイル群を spl_autoload_register に登録する
        $loader->register(true);

        return $loader;
    }
}

vendor/composer/ClassLoader.php (抜粋)

// spl_autoload_register を使って登録する
public function register($prepend = false)
{
    spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}


// spl_autoload_register によって呼ばれるメソッド
// ファイルが見つかれば include する
public function loadClass($class)
{
    if ($file = $this->findFile($class)) {
        includeFile($file);

        return true;
    }
}


// オードロード要求のクラスが含まれるファイルを探す
public function findFile($class)
{
    // classmap ファイルから読み込んだリストにいれば、それを返す
    if (isset($this->classMap[$class])) {
        return $this->classMap[$class];
    }

    // 「ファイルが見つからなかった」がキャッシュされていれば当然見つからない
    // あるいは dump-autoload のときに classmap-authoritative が指定されていれば classmap だけにする
    if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
        return false;
    }

    // APCu による最適化が有効になっていれば APCu から読み込めるか試みる
    if (null !== $this->apcuPrefix) {
        $file = apcu_fetch($this->apcuPrefix.$class, $hit);
        if ($hit) {
            return $file;
        }
    }

    // クラス名 .php のファイルを探す
    $file = $this->findFileWithExtension($class, '.php');

    // HHVM で動いているなら .hh ファイルを探す
    if (false === $file && defined('HHVM_VERSION')) {
        $file = $this->findFileWithExtension($class, '.hh');
    }

    // APCu 最適化が有効なら APCu にキャッシュ登録する
    if (null !== $this->apcuPrefix) {
        apcu_add($this->apcuPrefix.$class, $file);
    }

    // 「ファイルが見つからなかった」のキャッシュ
    if (false === $file) {
        // Remember that this class does not exist.
        $this->missingClasses[$class] = true;
    }

    return $file;
}


// クラス名 + 拡張子 のファイルを探すメソッド
private function findFileWithExtension($class, $ext)
{
    // PSR-4 形式のファイルを探す
    $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

    $first = $class[0];
    if (isset($this->prefixLengthsPsr4[$first])) {
        $subPath = $class;
        while (false !== $lastPos = strrpos($subPath, '\\')) {
            $subPath = substr($subPath, 0, $lastPos);
            $search = $subPath.'\\';
            if (isset($this->prefixDirsPsr4[$search])) {
                foreach ($this->prefixDirsPsr4[$search] as $dir) {
                    $length = $this->prefixLengthsPsr4[$first][$search];
                    if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
                        return $file;
                    }
                }
            }
        }
    }

    // PSR-4 のフォールバック
    // ※ 名前空間 => ディレクトリ名 という指定をしたもの
    foreach ($this->fallbackDirsPsr4 as $dir) {
        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
            return $file;
        }
    }

    // PSR-0 形式のファイルを探す
    if (false !== $pos = strrpos($class, '\\')) {
        // namespaced class name
        $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
            . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
    } else {
        // PSR-0 は PEAR 形式のファイル名も形容するので、それを探す
        $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
    }

    if (isset($this->prefixesPsr0[$first])) {
        foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
            if (0 === strpos($class, $prefix)) {
                foreach ($dirs as $dir) {
                    if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                        return $file;
                    }
                }
            }
        }
    }

    // PSR-0 のフォールバック
    // ※ プリフィックス => ディレクトリ名 という指定をしたもの
    foreach ($this->fallbackDirsPsr0 as $dir) {
        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
            return $file;
        }
    }

    // PSR-0 のインクルードパスの解決
    if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
        return $file;
    }

    // 見つからねーもんは見つからない。
    return false;
}


// 指定したファイルを include する
// ※これだけグローバル空間にいる
// ※includeしたものから $this や self を利用できないように、のため
function includeFile($file)
{
    include $file;
}

で、autoload_real から 読み込まれるファイルがいくつかあるけどなんやねん、という話は composer.json に書く。書き方はドキュメントに詳しくある。

The composer.json Schema - Composer

ざっくりとまとめると。

  • PSR-4
    • 名前空間でディレクトリを切る
    • プリフィックス : ディレクトリ名 として名前空間を設定できる
  • PSR-0
    • 名前空間でディレクトリを切る
    • プリフィックス : ディレクトリ名 として名前空間を設定できる
    • PSR-4 との違いは アンダースコアでも切ることができる、名前空間なしファイルが存在すること
  • classmap
    • 名前空間など PSR-0 または PSR-4 に従っていないもの
    • クラスのあるディレクトリやファイルを直に指定する
  • file
    • 細かいこととかいいから、俺はこのファイルを読み込みたいんだ

こんな感じ。 PSR-0 と PSR-4 はざっくりだけど、詳しく書くともっと長くなるのでまた。

 

オートローダーの最適化

このあたりのざっくりまとめ。

Autoloader Optimization - Composer

特にオプションなしに composer install または composer update 。 あるいは composer dump-autoload を実行すると、上記のまま処理が動く。

多数のライブラリを読み込むような巨大なフレームワーク、アプリケーションなどは、特に PSR-0 や PSR-4 のディレクトリ構成を解析して読み込む件で時間がかかってしまう。そこで、事前にオートローダーを最適化することができる。 -o オプションをつけるとよい。

$ composer dump-autoload -o

これで PSR-0 も PSR-4 も全てのオードロードの記述が classmap に変換される。 classmap になることで、クラス名からディレクトリを探しにいくことがなくなりその分高速化が見込める。

 
さらに本番環境など、ソースがもりもり変わることがなければ -a というオプションも付けるとよい。上のソース解説で出てきた classmap-authoritative のくだり。

$ composer dump-autoload -o -a

このオプションがあれば classmap に見つからないときに処理を諦める。そもそも composer dump-autoload なしに本番のソースが変わることはないだろうので、つけたほうが良い。が、可能性として、クラスが見つかりません!になってしまうことがある。

 
何かしらの都合で -a オプションはだめだー!となるなら APCu を有効にする戦略も取れる。 -a に比べて遅くはなるが、クラスが見つかりません!問題に対応しやすくなる。とはいえ APCu はメモリに乗っかってくるので、メモリに余裕があるような環境じゃないと使えない。

$ composer dump-autoload -o -apcu

上のソースを見てわかるとおり classmap-authoritative と APCu は同居しない、どちらかしか使えない。


複雑に絡み合ったひもがちょっとずつ解けていくように Composer の動きに詳しくなっていく気持ちがする。

が、ちょっとつかれたのでここでおちまい。

算術平均を逐次計算したい。

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

数式をこねくりまわす知識や技術はないので自分で求められないのですが、平均値って逐次計算できるのかな?を調べたメモ。

x = [...] // 元の数列
z = ...   // 追加したい数

// 平均値
Average(x) = Sum(x) / Count(x)

// 数を追加した平均値
Average(x + z) = Average(x) + ((z - Average(x)) / Count(x))

調べていたらこういう式も。平均に個数をかけて数を足し、そこから新しい個数で割れば、新しい平均だよね、というもの。そりゃそうだわ。

Average(x + z) = (Average(x) * Count(x) + z) / Count(x + z)

どちらにしても個数と平均値だけ持っておけば逐次計算できますね。後者は掛け算するので、個数や平均値が大きすぎると扱えなさそうなので、前者のほうがよさそう。

試しに実装してみるとこういう形。

class MeanStream
{
    private $mean = 0;
    private $dataCount = 0;

    public function __construct() {
    }

    public function add($num) {
        $this->dataCount++;
        $this->mean = $this->mean + (($num - $this->mean) / $this->dataCount);
        return $this;
    }

    public function get() {
        return $this->mean;
    }
}

echo new MeanStream()
    ->add(1)
    ->add(7)
    ->add(8)
    ->add(6)
    ->add(2)
    ->add(5)
    ->add(1)
    ->add(8)
    ->add(9)
    ->add(4)
    ->get();

echo (1+7+8+6+2+5+1+8+9+4) / 10;
// 5.1

あってますねー

 
ちなみに、当然のことながら上記の例だと浮動小数点数を使うので、使う値によっては表現の都合で微妙に数値が変わるのでその点だけ注意ですね。

$values = [];
for($i = 0; $i < 10; $i++) {
    $values[] = mt_rand();
}

$mean = new MeanStream();
foreach ($values as $value) {
    $mean->add($value);
}

echo sprintf('%.30f', array_sum($values) / count($values));
// 995988838.500000000000000000000000000000

echo sprintf('%.30f', $mean->get());
// 995988838.499999880790710449218750000000

PHP じゃない言語で実装するとして、もし Decimal のような、よろしく精度をもってくれる機能があればそれを使ってあげるほうがよさそうです。PHP は言語として標準に Decimal がないのでどうするんだろう、 bcmath とか gmp というのがありそうだけど extension に左右されるなー。まあ composer.json で extension について依存あるよーと記載すればいいのか。
PHP: 数学 - Manual

Packagist みると幾つかありそうなので、このあたりを使ったほうがいいのかなー。

 
と、話がそれてきたあたりでおしまい。ライブラリの話はまた今度。

Atom と Hydrogen で Jupyter が Atom で動くよ!(インストール、準備、使い方まで)

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

一時期 Atom を使ってたけど、もっさり感がどうにもならないのと、簡易的なメモ(新規ファイル作って保存せずメモしておきたい、エディタ再起動しても残っていてほしい)が残せなかったっぽいのもあって、しばらくずっと PhpStorm か SublimeText を使っています。

最近になって、普段使いの PC を新しいものに変更してスペックも上がったし Atom もいろいろバージョンアップしているようだしどうだろうなあ、と思って Atom のプラグインを色々見てたら Jupyter を触れるとかなんとか書いてあるではありませんか!
謎技術だなあと思いつつもエディタ上で Jupyter のように振る舞ってくれるならそれはとっても素敵だなーと思ったので、試してみたの巻。

 

Atom + Jupyter をやるには?

Hydrogen というパッケージを使うと Atom 上で Jupyter かのように一行ずつ実行したり、結果をグラフィカルに表示したりが出来ます。

内部的にはインストールされている Python で Jupyter を起動。 Jupyter が用意しているメッセージプロトコルを利用して nodejs と通信し、その結果を Atom で見えるように整形している、というものです。

参照)nteract/hydrogen: Run code inline in Atom using Jupyter kernels
※ How it works のくだり。

この Hydrogen を Atom にインストールしてやります。
それでは、順番に環境を準備していきましょう。

Atom

とくに言うことはないです。公式サイトからどうぞ。

Atom

Python の準備

こちらも同様に公式サイトからどうぞ。バージョンは 3 系で良いです。執筆時時点なら 3.6 あたりで良いと思います。
もし Windows を使っているなら Windows 用インストーラを選ぶとよいでしょう。

Welcome to Python.org

Jupyter の準備

少々雑ですが、いろいろ pip install したら良いです。

pip install -U pip

pip install ipython
pip install jupyter
pip install matplotlib

// 試しに利用したい //
pip install numpy
pip install scipy
pip install pandas
pip install scikit-learn

※ Windowsの場合
主に numpy と scipy と scikit-learn あたり(多分)でコンパイルエラーになってしまうので、別途配布しているサイトから whl ファイルをダウンロードして、それを使って登録する必要があります。

Python Extension Packages for Windows - Christoph Gohlke

pip install <ダウンロードした whl ファイル>

Hydrogen を入れる

Atom 内のパッケージ管理からインストールできます。Hydrogen で検索すれば一発でしょう。


(既にインストール済みなのでアンインストールボタンですが、通常はインストールボタンになります)

Atom + Hydrogen を試してみる

これ以上の準備は不要です。 Atom 上で Python を書いて、おもむろに Ctrl + Alt + Enter を押すと、勝手に Jupyter が裏で起動し、ソースを実行してくれます(スゴイ)
一括実行やブロック実行もできるので Jupyter がそのまんま Atom 上で動いているようにも見えます。

試しに numpy でランダムなデータを作成し KMeans で 5 つに色分けしてみた結果です。


 
キャプチャの通り Windows ですが scikit-learn も動きますし matplotlib の結果もちゃんと Atom 内で表示してくれます、スゴイ!!

え?Tensorflow?Chainer?
動くんじゃないですか? Atom で Python が動いている!!!ように見えるだけで、裏側は結局 Python + Jupyter でしかないので、それが動く環境なら動作するはずです。

Hydrogen の使い方

Jupyter ではそれぞれの Cell が明確に入力欄が別れていたり、なんとなく Ctrl + Enter を押したり、実行できそうなボタンを押すなどして動かしていましたが、 Hydrogen ではただの Atom エディタになるので明確に Cell の境界が見えることはありませんしどうなっているのでしょう。

公式ドキュメントにかかれていることとほぼおなじなので、そちらを見ている場合はこっちは見なくても良いです。
Getting Started · Hydrogen

コードの実行

デフォルトでは以下のようなキーバインドがされています。

キー コマンド 処理内容
ctrl-enter hydrogen:run 選択されているコードのみを実行する
ctrl-alt-enter hydrogen:run-cell 現在のセルを実行する
alt-shift-enter hydrogen:run-cell-and-move-down 今のセルを実行し、次のセルに移る
ctrl-alt-shift-enter hydrogen:run-all 全てのセルを実行する

セルを分けるには Jupyter と同じ記述の # In[ ]: という形を使うのが良さそうです。

# In[]:
x = 10
y = 10
(x, y)  # 10, 10

# In[]:
z = x * y
z  # 100

実際に試してる様子はこんな感じ。左からコード実行、セル実行、全実行。

カーネルの再起動

これはコマンドパレットから。なんか挙動がおかしいぞ?って時によく使いますよね。使わない…?

gif 見ての通り、再起動しても出力結果は消えないので、そこも消したいんだけど!!!という場合には Clear Result を別途実行する必要があります。

出力エリアのトグル

デフォルトでは、コードのすぐ下に出力されます。これはこれで便利ではあると思うのですが、コード量が増えてくるとうっとうしく感じることもあるかもしれません。 Hydrogen には出力エリアが準備されていて、それを開くことで、そちらに全て出るようになります。
しかもページ分けされて便利!

変数ウォッチ機能

これ Jupyter にありましたっけ…?あったら知らない私がごめんなさいなんですけど。。ともあれ、この機能めっちゃすごくないですか、変数を変えていくとリアルタイムで出力結果を確認できるんですよ…、どうなってんねん…。

クラス、関数のインスペクション

ライブラリだったり、自分で実装したクラスや関数について、説明を見ることが出来ます。公式ドキュメント片手にコードを書くことが多い私的には便利に使えそうです。

コード補完

ライブラリの中、変数の中に結局こういうメソッドってあったっけ?をドキュメントに見に行ったり私には非常に嬉しい機能です。
注意点としては、すぐ補完が効くわけではなく、その変数やクラスがカーネル側に認識されていないといけません。つまり、一度そのコードを実行して、認識させる必要があります。以下の gif では Ctrl+Enter を押して pred をカーネル側に認識させています。

おわりに

というわけで Atom + Hydrogen で Jupyter Notebook が使えるよ、って話でした。

Jupyter それ自体は非常に便利ですが、普段使うエディタを勝手が異なったりすると、それはそれで使いにくいですよね。。ショートカットキーだとか、テーマだとか…。。
Atom 自体がそこそこ重たいので、スペック高めのPCでないと難しいかもしれませんが、 Python 用のエディタとして Atom がかなり有力な選択肢になるんじゃないでしょうか?

ぜひお試しあれ!

形態素解析した後に結合処理をしてあげると良いかもね

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

こんにちは、ごみばこです。

MeCab や Kuromoji などで行える形態素解析、すごいですよねー。ただ新しい語が増えたり、なんだりーってしたときに、辞書を更新しないとちょっとだけ直感的ではない分割のされ方になりますよね。まあ、辞書を元に分割の仕方を学習するのでそうなんですが。。
そこに対して mecab-ipadic-neologd という素晴らしいプロジェクトがあって、最近の語もどんどん追加してくれています。

neologd/mecab-ipadic-neologd: Neologism dictionary based on the language resources on the Web for mecab-ipadic

これを使うと Github のサンプルにもかいてありますが「中居正広のミになる図書館」が固有名詞として認識されたりします!(スゴイ)

$ echo "10日放送の「中居正広のミになる図書館」(テレビ朝日系)で、SMAPの中居正広が、篠原信一の過去の勘違いを明かす一幕があった。" | mecab -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd
10日    名詞,固有名詞,一般,*,*,*,10日,トオカ,トオカ
放送    名詞,サ変接続,*,*,*,*,放送,ホウソウ,ホーソー
の      助詞,連体化,*,*,*,*,の,ノ,ノ
「      記号,括弧開,*,*,*,*,「,「,「
中居正広のミになる図書館        名詞,固有名詞,一般,*,*,*,中居正広のミになる図書館,ナカイマサヒロノミニナルトショカン,ナカイマサヒロノミニナルトショカン
」      記号,括弧閉,*,*,*,*,」,」,」
(      記号,括弧開,*,*,*,*,(,(,(
テレビ朝日      名詞,固有名詞,組織,*,*,*,テレビ朝日,テレビアサヒ,テレビアサヒ
系      名詞,接尾,一般,*,*,*,系,ケイ,ケイ
)      記号,括弧閉,*,*,*,*,),),)
で      助詞,格助詞,一般,*,*,*,で,デ,デ
、      記号,読点,*,*,*,*,、,、,、
SMAP    名詞,固有名詞,一般,*,*,*,SMAP,スマップ,スマップ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
中居正広        名詞,固有名詞,人名,*,*,*,中居正広,ナカイマサヒロ,ナカイマサヒロ
が      助詞,格助詞,一般,*,*,*,が,ガ,ガ
、      記号,読点,*,*,*,*,、,、,、
篠原信一        名詞,固有名詞,人名,*,*,*,篠原信一,シノハラシンイチ,シノハラシンイチ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
過去    名詞,副詞可能,*,*,*,*,過去,カコ,カコ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
勘違い  名詞,サ変接続,*,*,*,*,勘違い,カンチガイ,カンチガイ
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
明かす  動詞,自立,*,*,五段・サ行,基本形,明かす,アカス,アカス
一幕    名詞,一般,*,*,*,*,一幕,ヒトマク,ヒトマク
が      助詞,格助詞,一般,*,*,*,が,ガ,ガ
あっ    動詞,自立,*,*,五段・ラ行,連用タ接続,ある,アッ,アッ
た      助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
。      記号,句点,*,*,*,*,。,。,。
EOS

(サンプルそのまま)

もうこれを使ったら良いんじゃないかなあと思います。

が!やっぱり実際に様々な文言をいれていくと、そういう分け方になるのねーだったり、それはちょっといらないんだよなー、というパターンは発生します。なんていうんでしょうか、特徴語抽出とか、なんかそういうときにちょっと不便になるんですよきっと。
そんなころに、形態素解析した後に品詞を見て結合処理をすると良い、と風の噂で聞いたので試しました。

※ここからは都合によって mecab-ipadic を使っています。 neologd の結果ではないので注意。※

まずは結合処理無しのものを見てみましょう。

Target: 「3Dブロー方式」でスピード乾燥。のびる、ひろがる「ふとん乾燥アタッチメント」

[   ' BOS/EOS *',
    '「 記号 括弧開',
    '3 名詞 数',
    'D 名詞 一般',
    'ブロー 名詞 一般',
    '方式 名詞 一般',
    '」 記号 括弧閉',
    'で 助詞 格助詞',
    'スピード 名詞 一般',
    '乾燥 名詞 サ変接続',
    '。 記号 一般',
    ' BOS/EOS *',
    ' BOS/EOS *',
    'のびる 動詞 自立',
    '、 記号 一般',
    'ひろがる 動詞 自立',
    '「 記号 括弧開',
    'ふとん 動詞 自立',
    '乾燥 名詞 サ変接続',
    'アタッチメント 名詞 一般',
    '」 記号 括弧閉',
    ' BOS/EOS *']

短い文章ですが、「3」「D」と分かれていたり、「3」「D」「ブロー」「方式」はくっついていたほうがいいんじゃないかなあ、などなど。もうちょっと、なあ、という部分がありそうです(主観)
こういったものをはじめ、色々な文章をいれつつ、こっちのほうがいいなー、これはためだなー、などと、目視で結合処理を増やしていったロジックがこれです。
 

形態素解析の結果を1語ずつループし、以下の処理をしていく

  1. ()[]’" が出てきたら
    1. 次のループへ※
  2. 記号が出てきたら
    1. ただし、今が半角で構成されている、かつ、1つ前も半角であれば
      1. 1つ前に今の語を結合
      2. 次のループへ
    2. 次のループへ※
  3. 今が半角で構成されている、かつ、1つ前も半角であれば
    1. 1つ前に今の語を結合する
    2. 次のループへ
  4. 1つ前が接頭詞なら
    1. 1つ前に今の語を結合する
    2. 品詞を今のものに置き換える
    3. 次のループへ
  5. 今が接尾なら
    1. 1つ前に今の語を結合する
    2. 次のループへ
  6. 1つ前が名詞、かつ、形容動詞語幹なら
    1. 今が助詞、助動詞、副詞、非自立のいずれか
      1. 次のループへ※
    2. 新しい語として追加
    3. 次のループへ
  7. 今が非自立なら
    1. 1つ前に結合する
    2. 次のループへ
  8. 今が終助詞なら
    1. 1つ前に結合する
    2. 次のループへ
  9. 1つ前が名詞、かつ、今が名詞なら
    1. 1つ前が接尾なら
      1. 新しい語として追加
      2. 次のループへ
    2. 今が数なら
      1. 新しい語として追加
      2. 次のループへ
    3. 1つ前に結合する
    4. 次のループへ
  10. 1つ前が動詞または助動詞、かつ、今が動詞または助動詞なら
    1. 1つ前に結合する
    2. 次のループへ
  11. 1つ前が動詞または助動詞、かつ、今が助詞なら
    1. 1つ前に結合する
    2. 次のループへ
  12. 1つ前が形容詞、かつ、今が助動詞なら
    1. 1つ前に結合する
    2. 次のループへ
  13. 1つ前が助詞類接続、かつ、今が動詞なら
    1. 1つ前に結合する
    2. 次のループへ
  14. 1つ前が助詞、かつ、今が助詞なら
    1. 1つ前に結合する
    2. 次のループへ
  15. 今が接頭詞、あるいは、助詞類接続、あるいは、数なら
    1. 新しい語として追加
    2. 次のループへ
  16. 今が助詞、あるいは、助動詞、あるいは、非自立なら
    1. 次のループへ※
  17. 新しい語として追加
  18. 次のループへ

 

それではこのロジックで同じ文章を試してみましょう。

Target: 「3Dブロー方式」でスピード乾燥。のびる、ひろがる「ふとん乾燥アタッチメント」

[   '3Dブロー方式 名詞 数',
    'スピード乾燥 名詞 一般',
    'のびる 動詞 自立',
    'ひろがる 動詞 自立',
    'ふとん 動詞 自立',
    '乾燥アタッチメント 名詞 サ変接続']

結合したので、品詞や種類などはもう完全に意味をなしていませんが、先ほどよりも、なんだか自然な感じで単語が取れているのではないでしょうか?(主観)

というわけで結合するとよくなりそうだよ、って紹介でした。

sentencepiece ニューラルネット時代における新しトークナイザ

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

こんにちは、ごみばこです。

自然言語処理をするとき n-gram や形態素解析などの処理をし、文章から語にすることがよくあると思います。 n-gram はシンプルですが、分け具合、分け方によって情報量がなくなってしまうこともありますし、データ量も大きくなりがちです。形態素解析は簡単お手軽そうに見えますが、裏の処理はなかなかコストが高く、ちりもつもればなんとやら。

というところで、新しい選択肢の sentencepiece だそうです。

https://github.com/google/sentencepiece

私の知識や理解力の不足から雑な説明にはなってしまいますが…。sentencepiece が行うことは次のことです。

1. 文章をよろしくニューラルネットワークで処理し語に分割するためのモデルを生成
2. そのモデルを使って文章を分割する
3. n-gram や 形態素解析のような何かが得られる!やったー!

この何かで機械翻訳をすると n-gram や形態素解析などと比べて劣ることなく十分に効果を発揮した、との記録もあります。

https://github.com/google/sentencepiece#results-bleu-scores

学習する、という初期コストがかかることについては、形態素解析も同じですが、その後の分割することについては、形態素解析よりもコスト低く行うことができます。また、語彙も形態素解析で扱う辞書に比べて遥かに小さくできるそうで、パフォーマンスよし、効果よし、ととても魅力的に見えますね!

実際に収録されているサンプルを試してみました。

環境構築は docker でお手軽にやってしまいます。

$ docker run -it -d centos:latest
$ docker ps

$ docker attach ...

コンテナの中で必要なツールの準備を進めていきます。

# yum install git make gcc-c++ autoconf automake libtool protobuf protobuf-devel
# git clone https://github.com/google/sentencepiece.git
# cd sentencepiece
# ./autogen.sh
# ./configure
# make

ここまでで実行ファイルが作られます。それでは文章から学習をしてみます。
サンプルとして吾輩は猫である...が収録されているので、これを使ってみます。

# src/spm_train --input=data/wagahaiwa_nekodearu.txt --model_prefix=neko --vocab_size=8000 --model_type=unigram
unigram_model_trainer.cc(494) LOG(INFO) Starts training with :
input: "data/wagahaiwa_nekodearu.txt"
model_prefix: "neko"
model_type: UNIGRAM
vocab_size: 8000
character_coverage: 0.9995
input_sentence_size: 10000000
mining_sentence_size: 2000000
training_sentence_size: 10000000
seed_sentencepiece_size: 1000000
shrinking_factor: 0.75
num_threads: 16
num_sub_iterations: 2
max_sentencepiece_length: 16
split_by_unicode_script: true
split_by_whitespace: true

trainer_interface.cc(109) LOG(INFO) Loading corpus: data/wagahaiwa_nekodearu.txt
trainer_size=0ace.cc(126) LOG(INFO) Loading: ▁吾輩は猫である
trainer_interface.cc(148) LOG(INFO) Loaded 2246 sentences
trainer_interface.cc(166) LOG(INFO) all chars count=182657
trainer_interface.cc(173) LOG(INFO) Done: 99.9502% characters are covered.
trainer_interface.cc(181) LOG(INFO) alphabet size=2507
trainer_interface.cc(211) LOG(INFO) Done! 2246 sentences are loaded
unigram_model_trainer.cc(121) LOG(INFO) Using 2246 sentences for making seed sentencepieces
unigram_model_trainer.cc(149) LOG(INFO) Making suffix array...
unigram_model_trainer.cc(153) LOG(INFO) Extracting frequent sub strings...
unigram_model_trainer.cc(204) LOG(INFO) Initialized 34678 seed sentencepieces
trainer_interface.cc(215) LOG(INFO) Tokenizing input sentences with whitespace: 2246
trainer_interface.cc(224) LOG(INFO) Done! 2193
unigram_model_trainer.cc(513) LOG(INFO) Using 2193 sentences for EM training
unigram_model_trainer.cc(529) LOG(INFO) EM sub_iter=0 size=19246 obj=303.949 num_tokens=81388 num_tokens/piece=4.22883
unigram_model_trainer.cc(529) LOG(INFO) EM sub_iter=1 size=17546 obj=276.547 num_tokens=81681 num_tokens/piece=4.65525
unigram_model_trainer.cc(529) LOG(INFO) EM sub_iter=0 size=13133 obj=282.685 num_tokens=85486 num_tokens/piece=6.50925
unigram_model_trainer.cc(529) LOG(INFO) EM sub_iter=1 size=13089 obj=279.841 num_tokens=85549 num_tokens/piece=6.53595
unigram_model_trainer.cc(529) LOG(INFO) EM sub_iter=0 size=9814 obj=292.604 num_tokens=91023 num_tokens/piece=9.27481
unigram_model_trainer.cc(529) LOG(INFO) EM sub_iter=1 size=9813 obj=289.388 num_tokens=91093 num_tokens/piece=9.28289
unigram_model_trainer.cc(529) LOG(INFO) EM sub_iter=0 size=8799 obj=294.594 num_tokens=93339 num_tokens/piece=10.6079
unigram_model_trainer.cc(529) LOG(INFO) EM sub_iter=1 size=8799 obj=293.481 num_tokens=93368 num_tokens/piece=10.6112
trainer_interface.cc(284) LOG(INFO) Saving model: neko.model
trainer_interface.cc(293) LOG(INFO) Saving vocabs: neko.vocab

学習が完了しました。適当な文章を入れて、分割の様子を見てみましょう。

# echo "吾輩は猫である。名はまだ無い。" | src/spm_encode --model=neko.
▁吾輩は 猫 である 。 名 はまだ 無い 。

# echo "吾輩は箱が好きで好きでたまらない。" | src/spm_encode --model
▁吾輩は 箱 が 好き で 好き で たま らない 。

# echo "ニャーと声を出せばで飯が提供され、ニャッと声を出せば頭を撫でられる。" | src/spm_encode --model=neko.model
▁ ニ ャ ー と 声を 出 せば で 飯 が 提 供 され 、 ニ ャ ッ と 声を 出 せば 頭 を撫 で ら れる 。

私自信の知識と能力が追いついていないのもあって、どんなところで使えそうなのかあまりイメージわかないですが、トークナイザの1つの選択肢として考えたいですねー!

関連リンク)
http://qiita.com/taku910/items/7e52f1e58d0ea6e7859c
どういった背景から作られたかが解説されています!

CSV ファイルで文字化けするんだけど!!!を調べた

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

こんにちは、ごみばこです。

CSV ファイルってデフォルトでエクセルを使って開けるんですけど、どうにも文字コードを上手いことしてあげないとだめなんですよね。ということで幾つかの組み合わせについてぐぐったり、試したり、調べたのでメモ程度にー。
(ぐぐったらいろんな人が書いていて今更感もありますが・・・)

試したコードはこちら

<?php
// http://php.net/manual/ja/mbstring.supported-encodings.php
$encoding = [
	'UTF-8',
	'UTF-16BE',
	'UTF-16LE',
	'UTF-32BE',
	'UTF-32LE',
	'EUC-JP',
	'SJIS',
	'SJIS-win',
	'ISO-2022-JP',
	'CP932',
];

// https://ja.wikipedia.org/wiki/%E3%83%90%E3%82%A4%E3%83%88%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%E3%83%9E%E3%83%BC%E3%82%AF
$bom = [
	'UTF-8' => chr(0xEF) . chr(0xBB) . chr(0xBF),
	'UTF-16BE' => chr(0xFE) . chr(0xFF),
	'UTF-16LE' => chr(0xFF) . chr(0xFE),
	'UTF-32BE' => chr(0x00) . chr(0x00) . chr(0xFE) . chr(0xFF),
	'UTF-32LE' => chr(0xFF) . chr(0xFE) . chr(0x00) . chr(0x00),
];

$ary = ['abcdef', 'テスト', 'ほげほげ', '??'];
ob_start();
echo '"' . implode('","', $ary) . '"'; // とりあえず雑に...
$buf = ob_get_flush();

// bom なし
foreach($encoding as $e) {
	file_put_contents("{$e}.csv", mb_convert_encoding($buf, $e));
}

// bomあり版
foreach($encoding as $e) {
	if (empty($bom[$e])) {
		continue;
	}

	file_put_contents("{$e}_bom.csv", $bom[$e] . mb_convert_encoding($buf, $e));
}

寿司ビールが正しく出れば Unicode も適切に処理されているはずなので安心安全ですね!

では結果を順番に見ていきましょう。















まとめるとこんな感じですね!

・CP932 や SJIS, EUC-JP などでは案の定、寿司ビールは出ません。
・UTF では BOM ありでないと文字化けしてしまいました。
・UTF-16 では LE にする必要がありました。
・UTF-16 では他のものと異なり、自動でカンマ部分の解釈がされないようでした。
・UTF-32 はダメです。

というわけで、とりあえず UTF-8 BOM あり にしておけば、色々と安心安全に動くんじゃないかなーと思います。

または、どうしても表でほしいなら xlsx を直にいじくりまわす、ですかねー。
PHP なら phpexcel 。Java なら POI 。Python なら xlrd + pandas 。
などと様々な言語から xlsx を利用する手立てがあります(あたまの良い人ありがとう)ので、これらを使っていくことも検討すべきかと思います。まあ、つらいところもあるので、難しいものなら、そもそもいる?、なんて話にした方がいいよいかもしれませんね!

pv コマンド便利だよって

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

こんにちは、ごみばこです。

pv コマンド絶妙に便利なのですが、使う機会も少ないので、忘録的に書いときます。

pv ??

ivarch.com: Pipe Viewer

pv = pipe viewer の略で、その名の通り、パイプ処理のときのデータ量を可視化してくれて、絶妙に役立ちます。

pv をインストール

debian 系なら apt-get で、特に何することなくインストールするとこができます。Redhat もとい CentOS では RPMForge を導入することで yum install pv でインストールできます。

RepoForge Project

RPMForge は終了したそうです。理由としては、メンテナンスされていない古いソフトウェアが増えてきたから、とのこと。。というわけで Redhat/CentOS な方々は pv の公式サイトから rpm が公開されているので、これを利用すると良さそうです。

http://www.ivarch.com/programs/rpms/pv-1.6.6-1.x86_64.rpm

※バージョンは要確認すること。

$ sudo rpm -ivh http://www.ivarch.com/programs/rpms/pv-1.6.6-1.x86_64.rpm
$ pv --version

pv を使う

たとえば圧縮された SQL をドバーッと mysql に流したい…。

$ bzcat dump.sql.bz2 | mysql -uroot -pxxxx

が、これでは、ちゃんと進んでいるのかわからにくい! ここで pv を使うと…

$ bzcat dump.sql.bz2 | pv | mysql -uroot -pxxxx
1.81GiB 0:02:31 [ 12.4MiB/s] [                      <=>           ]

こんな出力がされ、流れるデータ量が可視化されます!

更に pv は複数に渡って記述ができるので…
(公式サイトに記載されているものとほぼ同じですが。。)

$ pv -cN source < dump.sql.bz2 | bzcat | pv -cN bzcat | mysql -uroot -pxxxx
    bzcat:  109MiB 0:00:18 [7.60MiB/s] [            <=>                     ]
   source: 52.7MiB 0:00:19 [3.89MiB/s] [=====>              ] 27% ETA 0:00:50

終わりそうな目処感と流れるデータ量を可視化できます!

まとめ

pv を使うことでパイプに流れるデータ量を観測することができます。これによっていつ終わるのか不安に思える作業もある程度は見える化されて便利~!

PhpStorm で Python のシンタックスハイライトを利用する

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

こんにちは、ごみばこです。

これまで SublimeText ユーザだったのですが、ここのところずっとPHP書きがおおいので、本格的に PhpStorm に乗り換えました。やっぱり IDE すごいっすねー、静的解析強力過ぎやしませんかね。

PhpStorm: Lightning-Smart IDE for PHP Programming by JetBrains

という話は今回ではないのですが。

PHP も書きつつ、機械学習だなんだーとやる機会もあって Python を書くことも増えてきました。そこで PhpStorm でも Python のハイライトくらいはできるよーって紹介です。

PyCharm があるよね?

PhpStorm と同じく JetBrain 社から PyCharm という Python 向けの IDE も出ています。が、これを使うにはまた別途ライセンスを買わないと。。そこまでガッツリと書いているわけでもないしなあ。。。ということで基本的に SublimeText を使って Python を書いています。

PyCharm: Python IDE for Professional Developers by JetBrains

ある日、ふと PhpStorm も IDE だし、プラグインかなにかでハイライトくらいはできるんじゃないの? と思い調べたところ、スルッと出来ました。ただし、できるのはハイライトまでで、静的解析やその他の言語サポートは利用できません。PhpStorm にある機能(検索、置換、etc...)ならばできます。

背景には PHP と Python とが合わさったプロジェクトをやることがあり、エディタを度々切り替えるのもなんだかなーまとめられないかなー、というところからです。

TextMate Bundles Support

TextMate はご存知でしょうか?

textmate/textmate: TextMate is a graphical text editor for OS X 10.9+

Mac 向けのテキストエディタなのですが、そのエディタで使える言語定義ファイルである tmbundle を PhpStorm はじめとした各種の JetBrain 社の IDE で利用することができます。これによりプラグインを含めて IDE がサポートしていない言語、設定ファイルなどをハイライトすることができます。

そんな機能を使うには、まず TextMate Bundles Support を有効化する必要があります。

plugins -> textmate bundles support

次に tmbundle ファイルを探します。これは TextMate オーガナイゼーションに多数あるので、そこから探すと良いでしょう。ここでは python.tmbundle をダウンロードします。

Search · org:textmate tmbundle

textmate/python.tmbundle: TextMate support for Python

このファイルは、どこかわかりやすい場所にまとめると良いでしょう。
そうして準備ができたファイルを PhpStorm で読み込みます。

settings -> editor -> textmate

このとき TextMate と PhpStorm とで、カラースキーマを合わせる設定をします。IDE Color Schema に合わせて TextMate Color Schema を設定していきます。私の場合は Monokai copy という名前で Monokai をちょっと弄ったものを使っているので、これに合わせて Monokai を選びます。(すべて Monokai になっていますが使っているテーマに合わせて、だけでよいです。)

 

以上で設定は完了です。これで Python がシンタックスハイライトされるようになりました。カッコが気持ち悪いのは autopep8 したからです。。

まとめ

PhpStorm でも TextMate Bundles Support を有効にすることで言語定義ファイルの tmbundle を利用できるようになりました。このファイルをどんどん入れていけば、他の言語もハイライトされるようになっていきます。TextMate リポジトリを見てわかるように、かなりの定義ファイルがあります。

ただ、仕事や趣味問わずですが、ガッツリと使っていく予定があるならば、言語環境にあったエディタや IDE を利用したほう生産性も上がっていくと思います。余程のエディタ愛があるならともかく、環境に合わせて使う道具も切り替えていきたいですね!

ガチで書くわけではなく、ちょっとやりたいんだよね、というくらいなら tmbundle で十分だと思います。ぜひお試しください!

gomiba.co.in を https にした

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

目次

  • https
  • Let’s Encrypt
  • 導入していく
  • おわり

こんにちは、ごみばこです

実はさらっと、ごみばこいんを https にしてました。
以前にも一度やっていたのですが、何かに詰まり、元に戻していました。またやったら特に問題なく出来てしまったので、何だったんだろう…。。

個人のひっそりページで証明書買うのもなあ、ということで Let's Encrypt でhttps化を行いました。

そのやったことなんかを簡単に説明していきます。

https

http 通信ではなく https 通信にすると、クライアントとサーバ間の通信経路が暗号化されます。
暗号化することによって、なりすまし、改ざん、盗聴といった、第三者による介入を回避することが可能になります。
webを安全に、フリーに扱うことができるようになります。

暗号化は、サーバから配送される証明書(=公開鍵)を用いて、サーバ上の鍵ファイル(=秘密鍵)を使った、公開鍵暗号方式となります。
もっと詳細な https プロトコルについてあまり詳しくはないので、

この証明書は、自分の手でも作ることができますが、信用された機関から発行されたものでないと、クライアントが証明書を信用することができません。
信用された機関も、むやみに証明書を発行することはなく、実在性や正当性を確認したうえで発行します。

具体的にはもっといろいろと計算やサーバ・クライアント間のやりとりがあるのですが、ぼくが https プロトコルに詳しくないので、このあたりで。。汗

こういったwebページが参考になるかもです。
https://www.symantec.com/ja/jp/ssl-certificates/

Let’s Encrypt

https://letsencrypt.org/

Let’s Encrypt は無料で、自動で、オープンな証明機関です。さっきまでの話と異なりますね。

近年のインターネット、webの発達を受けて、もっと安全に利用できるように https を推進している団体(EFF)がいて、ここに web やセキュリティに強い企業が手伝って、いろいろないろいろが出来ているようです。
(詳しく見れていない。。。)

で、今回ごみばこいんは、こちらの Lets’s Encrypt を利用して https にしましたよー、という話です。

導入していく

Let’s Encrypt を利用するには ACME という証明書を発行するプロトコルを使って、証明書を発行する必要があります。
そのプロトコルでやりとりできるツールの一つが certbot です。

ACME プロトコル
https://ietf-wg-acme.github.io/acme/

certbot
https://certbot.eff.org/

ごみばこいんでは、以前 Let’s Encrypt を試そうとしていたところもあったので、一度これを消去します。
※ルートのホームディレクトリに居ただけ

# rm -rf ~/letsencrypt/

certbot を導入します。

# wget https://dl.eff.org/certbot-auto
# chmod a+x certbot-auto

起動確認

# ./certbot-auto 

私の環境では Python 2.6 しかいなかったようなので(!?) Python 2.7 を入れました

# wget https://centos6.iuscommunity.org/ius-release.rpm
# rpm -ivh ius-release.rpm
# yum install python27 python27-devel python27-pip python27-setuptools python27-virtualenv
# rm ius-release.rpm 

再び起動確認

# ./certbot-auto

certbot-auto が使えるようになったことが分かったので、プロパティを設定し、証明書を発行していきます

# ./certbot-auto certonly --webroot -w /var/www/html/ -d gomiba.co.in -m webmaster@gomiba.co.in --agree-tos

ごみばこいんでは nginx を利用しているので、この設定を変更し https を有効にします。

# vi /etc/nginx/conf.d/server.conf 

↓こんな感じのものを書き足しました

server {
    listen 443;

    ssl on;

    # ※certbotを実行したときにパスが出ると思うのでそれを使います!
    ssl_certificate /etc/letsencrypt/live/gomiba.co.in/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/gomiba.co.in/privkey.pem;

    # ※https で使える暗号方式ですが、古い暗号方式は脆弱性があるなどなので無効化するのが吉です
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:!DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!ECDHE-RSA-DES-CBC3-SHA:!ECDHE-ECDSA-DES-CBC3-SHA;


    # 有効なプロトコル
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    # セッションをキャッシュすることでCPUに余裕を持たせます
    ssl_session_cache shared:SSL:5m;

    # ※ドキュメントルートの設定など
}

※暗号方式のところは、設定後にチェックツールを利用するのがおススメです
https://globalsign.ssllabs.com/

nginx を再起動

# service nginx restart

https で接続ができるか確認し、無事に出来たのでこれにておしまいです。

ちなみに Let’s Encrypt で発行した証明書は90日で期限が切れてしまうので、crontab で自動更新するのが良いです。これは certbot のユーザガイドにも書かれています。

# crontab -e

↓こんな内容を記述

# certbot
0 12 * * * /root/certbot-auto renew -q --no-self-upgrade --post-hook "service nginx reload"

これで Let’s Encrypt がサービス終了にならない限り、ずっと https が利用できます。

おわり

certbot を使うと、簡単に証明書を発行でき https を有効にすることができました。

Let’s Encrypt で発行される証明書を有料の証明書と比べる比べると、企業や団体としての存在証明を行うことはできないので、より信頼性の高める必要のある web サイトで利用することは難しいかもしれませ。しかし、個人で利用する程度のものでは十分だと思います。

安全な web サイトにするためにも、ぜひ使っていきましょう!

激安 JS を作ってみた

この記事は公開されてから1年以上経過しており、情報が古い可能性があります。

こんにちは。ごみばこです。

某所で激安 CSS が盛り上がり、実際に使うとなったら JS に全部書かれていて、数字だけ入った要素に適用されると嬉しいだろうなあ~、と思ったので、作ってみました。

※激安 CSS についてはこちら > http://qiita.com/shiozaki/items/0e42e101b7483df13c8f

ソースはここ(gist)
✨安い!!お得!!激安JS!!✨

せっかくなので、ただ作るではなく、普段書かないようなメソッドや記述を盛り込んでみようかなあと。

  • ライブラリを使わない
  • document.querySelector と document.querySelectorAll で要素検索
  • テンプレートリテラルで CSS の定義
  • innerHTML じゃなくて createElement で地道に作っていく
  • let! let!
  • アロー関数でクロージャ

 

↓実際に実行するとこちらになります

 

あの大人気の掃除機が今だけナント!49800


<p>あの大人気の掃除機が今だけナント!<span class="gekiyasu">49800</span></p>
<script src="/tool/gekiyasu.js"></script>
<script>gekiyasu.initialize();</script>

 

元の CSS 作者に圧倒的感謝?

1 2 3 4 5 6 7 8 9 10 11 12 13