20190323のPHPに関する記事は10件です。

php3を終えて

こんにちは
未来電子テクノロジーでインターンをしています
今回はphp3を終えての学びをアウトプットします

クラスプロパティ

クラスプロパティとは個々のインスタンスではなく、クラスに関するプロパティのことだ 
staticを用いることで表現できる

継承

すでにできているプロパティをほかのクラスに移すことを指す
継承は class class名 にextendsをつけることで表現できる
引き継がれたクラス(子クラス)は親クラスのプロパティなどの要素をそのまま引き継いでいる
また子クラスには独自のメゾットを定義することもできる
定義の際には通常の定義と同じく、public functionを使うことで表現できる
独自メゾットは親クラスには反映されないので注意が必要だ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

php2を終えて

こんにちは
未来電子テクノロジーでインターンをしています。
今回はphp2を終えた学びをアウトプットしたいと思います。

オブジェクト思考


オブジェクト思考とはそのもののできる要素のこと
プログラミングでも現実世界と同じように複数の要素からデータができている

クラス

クラスとはオブジェクト1つ1つの要素を作るためのもの
<?php class クラス名 ?>で表現できる

よく使う表現

*$this
$thisはメソッドを呼び出す際に使用する
異なるメソッド間でやり取りをするとコードが複雑になる
そのため、$thisを用いてコードを簡略化する
*__contrust
__contrustはインスタンスを作成する際に使用する
引数を代入することもできるので便利である

カプセル化

カプセル化とは回路を隠すことを意味する
通常のpublicを用いたコードだと誰でも介入が可能になる
しかし、システムの内部に関する部分までpublicで作成すると、情報を変えられる可能性がある
そのため、priveteを用いてカプセル化をして情報を隠す

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ZabbixのPHPをバージョンアップする。

1. はじめに

Centos7系のPHPはバージョン5.4が入っていると思います。
PHPの5系はサポートが切れていることと、Wordpressを同じサーバーで運用したいと思ったので、PHPを7.3にバージョンアップしようと思います。
Zabbixは4.0が稼働中ため、PHPのバージョンアップに併せて、Zabbix側の設定変更も行います。
こちらは個人の環境(VPS)で実施しています。本番環境でやる場合は、ご注意ください。

2. PHP5.4のアンインストール

  • 作業前の確認として、PHP関連でインストールされているものを確認します。
# rpm -qa | grep php
php-cli-5.4.16-46.el7.x86_64
php-pdo-5.4.16-46.el7.x86_64
php-common-5.4.16-46.el7.x86_64
php-5.4.16-46.el7.x86_64
php-mysql-5.4.16-46.el7.x86_64
php-bcmath-5.4.16-46.el7.x86_64
php-xml-5.4.16-46.el7.x86_64
php-gd-5.4.16-46.el7.x86_64
php-mbstring-5.4.16-46.el7.x86_64
php-ldap-5.4.16-46.el7.x86_64
  • /etc/php.iniはバックアップしておいて、バージョンアップ後のコンフィグにデフォルトから変更した内容を反映出来るようにしておくと良いと思います。

  • 下記コマンドで既存のPHP5.4をアンインストールします。

# yum delete php

==============================================================================================================
 Package                        Arch                 Version                      Repository             Size
==============================================================================================================
Removing:
 php                            x86_64               5.4.16-46.el7                @base                 4.4 M
Removing for dependencies:
 zabbix-web                     noarch               4.0.5-1.el7                  @zabbix                16 M
 zabbix-web-mysql               noarch               4.0.5-1.el7                  @zabbix               0.0

Transaction Summary
==============================================================================================================
Remove  1 Package (+2 Dependent packages)

依存の関係で、zabbix-webとzabbix-web-mysqlもアンインストールされました。
こちらも、PHP7.3のインストールに併せて、インストールします。

  • PHP関連のものがまだ残っていたので、アンインストールします。

# yum delete php-common

3. PHP7.3のインストール

  • 私の環境ではEPELリポジトリは導入済みだったので、Remiリポジトリを追加します。

# yum install https://rpms.remirepo.net/enterprise/remi-release-7.rpm

  • もともと入っていたPHP関連のパッケージをインストールします。

# yum install --enablerepo=remi --enablerepo=remi-php73 php php-cli php-pdo php-common php-mysql php-bcmath php-xml php-gd php-mbstring php-ldap zabbix-web zabbix-web-mysql

ですが、下記のようにzabbix-web-mysqlの依存でエラーになりました。

--> Processing Dependency: php-mysql for package: zabbix-web-mysql-4.0.5-1.el7.noarch
Package php-mysql is obsoleted by php-mysqlnd, but obsoleting package does not provide for requirements
--> Finished Dependency Resolution
Package php-mysql is obsoleted by php-mysqlnd, but obsoleting package does not provide for requirements
--> Finished Dependency Resolution
Error: Package: zabbix-web-mysql-4.0.5-1.el7.noarch (zabbix)
           Requires: php-mysql
           Available: php-mysql-5.4.16-46.el7.x86_64 (base)
               php-mysql = 5.4.16-46.el7
           Available: php-mysql-5.4.45-16.el7.remi.x86_64 (remi)
               php-mysql = 5.4.45-16.el7.remi
           Available: php-mysql-5.4.45-17.el7.remi.x86_64 (remi)
               php-mysql = 5.4.45-17.el7.remi
           Available: php-mysqlnd-5.4.16-46.el7.x86_64 (base)
               php-mysql = 5.4.16-46.el7
           Available: php-mysqlnd-5.4.45-16.el7.remi.x86_64 (remi)
               php-mysql = 5.4.45-16.el7.remi
           Available: php-mysqlnd-5.4.45-17.el7.remi.x86_64 (remi)
               php-mysql = 5.4.45-17.el7.remi
           Available: php-pecl-mysql-1.0.0-0.20.20180226.647c933.el7.remi.7.3.x86_64 (remi-php73)
               php-mysql = 1:1.0.0
           Available: php-mysqlnd-7.3.2-1.el7.remi.x86_64 (remi-php73)
               Not found
           Available: php-mysqlnd-7.3.3-1.el7.remi.x86_64 (remi-php73)
               Not found
 You could try using --skip-broken to work around the problem
 You could try running: rpm -Va --nofiles --nodigest

検索すると下記情報が見つかりました。
https://www.sodo-shed.com/archives/12584
PHP7系には、php-mysqlはなくphp-mysqlndが入っていれば問題なさそうです。

先ほど実行したコマンドから「zabbix-web-mysql」を削除して実行します。

# yum install --enablerepo=remi --enablerepo=remi-php73 php php-cli php-pdo php-common php-mysql php-bcmath php-xml php-gd php-mbstring php-ldap zabbix-web

今度はエラーは出ず、インストールされるはずです。

  • zabbix-web-mysqlは個別にrpmでインストールします。

# wget https://repo.zabbix.com/zabbix/4.0/rhel/7/x86_64/zabbix-web-mysql-4.0.5-1.el7.noarch.rpm
# rpm -ivh --nodeps zabbix-web-mysql-4.0.5-1.el7.noarch.rpm

  • インストールしたパッケージを確認します。
# rpm -qa | grep php
php-json-7.3.3-1.el7.remi.x86_64
php-mysqlnd-7.3.3-1.el7.remi.x86_64
php-bcmath-7.3.3-1.el7.remi.x86_64
php-ldap-7.3.3-1.el7.remi.x86_64
php-common-7.3.3-1.el7.remi.x86_64
php-gd-7.3.3-1.el7.remi.x86_64
php-pgsql-7.3.3-1.el7.remi.x86_64
php-cli-7.3.3-1.el7.remi.x86_64
php-xml-7.3.3-1.el7.remi.x86_64
php-mbstring-7.3.3-1.el7.remi.x86_64
php-pdo-7.3.3-1.el7.remi.x86_64
php-7.3.3-1.el7.remi.x86_64
# rpm -qa | grep zabbix
zabbix-web-mysql-4.0.5-1.el7.noarch
zabbix-server-mysql-4.0.5-1.el7.x86_64
zabbix-release-4.0-1.el7.noarch
zabbix-web-4.0.5-1.el7.noarch
zabbix-agent-4.0.5-1.el7.x86_64
zabbix-web-pgsql-4.0.5-1.el7.noarch
zabbix-get-4.0.5-1.el7.x86_64

4. PHPバージョンアップに伴う設定変更

  • 「/etc/httpd/conf.d/zabbix.conf」の設定変更をします。
    <IfModule mod_php5.c>

    <IfModule mod_php7.c>

  • PHPの設定変更をします。
    Zabbixに関しては「/etc/php.ini」で「date.timezone = Asia/Tokyo」とすれば良いはずです。

  • 設定反映のためhttpdを再起動します。
    # systemctl restart httpd.service

5. 正常性の確認

Zabbixのダッシュボードにログイン出来ることを確認します。
https://ホスト名/zabbix/
各種ログを見て、エラーが出ていないか確認します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP 3項演算子

3項演算子の使い方

知らなかったのでメモです。

要約

  • 条件演算子のうちの一つ
<?php
// 三項演算子の使用例
$action = (empty($_POST['action'])) ? 'default' : $_POST['action'];

// 上記は以下の if/else 式と同じです。
if (empty($_POST['action'])) {
    $action = 'default';
} else {
    $action = $_POST['action'];
}

?>

書き方

(式1) ? (式2) : (式3);
式1の条件がTRUE(つまり、合ってるよーって時)、式2が発動する。
式1の条件がFALSE(つまり、間違ってるよーって時)、式3が発動する。

そんな感じです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ディレクトリの容量を確認する方法

disk_total_spacedisk_free_space関数が使える場合は簡単に計算できます。

<?php
$si_prefix = array('B', 'KB', 'MB', 'GB', 'TB', 'EB', 'ZB', 'YB');
$base = 1024;
$path = '/';

$total_bytes = disk_total_space($path);//全体サイズ
$free_bytes = disk_free_space($path);//空き容量

$used_bytes = $total_bytes - $free_bytes;
$class = min((int)log($used_bytes, $base), count($si_prefix) - 1);
echo '使用容量:'.sprintf('%1.2f', $used_bytes / pow($base,$class)).$si_prefix[$class];

レンタルサーバーの場合

サーバーがレンタルサーバーなどの場合はdisk_total_spaceで正しい数値がでないため
下記のように直接ファイルサイズを足していきます。

<?php
$si_prefix = array('B', 'KB', 'MB', 'GB', 'TB', 'EB', 'ZB', 'YB');
$base = 1024;

function dir_size($dir) {
  $handle = opendir($dir);
  while ($file = readdir($handle)) {
    if ($file != '..' && $file != '.' && !is_dir($dir.'/'.$file)) {
      $mas += filesize($dir.'/'.$file);
    } else if (is_dir($dir.'/'.$file) && $file != '..' && $file != '.') {
      $mas += dir_size($dir.'/'.$file);
    }
  }
  return $mas;
}

$used_bytes = dir_size(dirname(__FILE__));
$class = min((int)log($used_bytes, $base), count($si_prefix) - 1);
echo '使用容量:'.sprintf('%1.2f', $used_bytes / pow($base,$class)).$si_prefix[$class];

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】ディレクトリの容量を確認する方法

disk_total_spacedisk_free_space関数が使える場合は簡単に計算できます。

bytes_check.php
<?php
$si_prefix = array('B', 'KB', 'MB', 'GB', 'TB', 'EB', 'ZB', 'YB');
$base = 1024;
$path = '/';

$total_bytes = disk_total_space($path);//全体サイズ
$free_bytes = disk_free_space($path);//空き容量

$used_bytes = $total_bytes - $free_bytes;
$class = min((int)log($used_bytes, $base), count($si_prefix) - 1);
echo '使用容量:'.sprintf('%1.2f', $used_bytes / pow($base,$class)).$si_prefix[$class];

レンタルサーバーの場合

サーバーがレンタルサーバーなどの場合はdisk_total_spaceで正しい数値がでないため
下記のように直接ファイルサイズを足していきます。

bytes_check.php
<?php
//使用容量の数値(バイト)
function dir_size($dir) {
  $handle = opendir($dir);
  while ($file = readdir($handle)) {
    if ($file != '..' && $file != '.' && !is_dir($dir.'/'.$file)) {
      $mas += filesize($dir.'/'.$file);
    } else if (is_dir($dir.'/'.$file) && $file != '..' && $file != '.') {
      $mas += dir_size($dir.'/'.$file);
    }
  }
  return $mas;
}

//数値の単位を変更
function used_bytes($dir){
  $si_prefix = array('B', 'KB', 'MB', 'GB', 'TB', 'EB', 'ZB', 'YB');
  $base = 1024;
  $dir_size = dir_size($dir);
  $class = min((int)log($dir_size, $base), count($si_prefix) - 1);
  $used_bytes = sprintf('%1.2f', $dir_size / pow($base,$class)).$si_prefix[$class];
  return $used_bytes;
}
echo "使用容量:".used_bytes(dirname(__FILE__));

used_bytes($dir)で出力します。
$dirには絶対パスを指定してください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Wordpress:投稿と一緒に使われている画像も削除する

function.phpに記入します

add_action( 'before_delete_post', 'delete_post_attachment' );
function delete_post_attachment( $post_id ) {
  $args = array(
    'numberposts' => -1,
    'post_parent' => $post_id,
    'post_type' => 'attachment',
    'post_status' => 'any',
    'post_mime_type' => 'image'
  );
  $attachments = get_children( $args );
  foreach( $attachments as $attachment ) {
     wp_delete_attachment( $attachment->ID, true );
  }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

NULLについての一つの解釈

Abstract

先日PHPのサーバーサイドプログラミングの勉強を始め、
テキストフォーム送信のHTTPリクエストの条件分岐処理について勉強しているとき、
nullについての理解に迫られた。

NULLとは、あらゆるプログラム言語において、値の状態を表す特殊な値である。

数字の零を意味するドイツ語のnullからきていると思われる。

NULLとかくと、それは「NULL型の値『NULL』」として解釈される。

NULLとは一体なんなのか。

初心者の私が畏れ多いが、nullというものについて、以下に私なりの解釈(仮説)を述べたいと思う。
妥当性を欠いている箇所、考え方全体の違和感、等あれば、ご指摘頂ければ幸いである。

nullとは(私の解釈)

あるとき、世のプログラマーたちは、
「あらゆる種類の値に、2種類の『状態』をもたせたい」と考えた。

そこで、この二つの状態を区別するために、『null型』というデータ型が作られた。

これにより、あらゆる種類の値は、
『null型の値』と『null型でない値』
という具合に、値を二つの状態に分けることができるようになった。

プログラマーたちは
『null型の値』と『null型でない値』に対して、以下のようにコマンドを割り当てることにした:

『null型の値』:中身がnullの変数(または定数)、中身が定義されていない変数(または定数)、中身が""の変数(または定数)
『null型でない値』:上以外の全ての値

これにより、例えば以下のように定義された変数は全てnull型:

var hogehoge = null;
var foo;
var hensuu = "";

であり、
以下のように定義されたされた変数(または定数)はnull型でない諸データ型:

var zero = 0;//整数型数値「ゼロ」
var hogehoge = 114514;//整数型数値「114514」
var foo ="こんにちは";//文字列「こんにちは」
var boolean = true;//ブール値「true」
var PI = 3.14;//実数型数値「3.14」

という具合に分けられるようになった。

この構造を使って、彼らは、
前者のように、ある値があって、それがnull型であることを、「その値は『null』である」
後者のように、ある値があって、それがnull型でないことを、「その値は『普通の値』である」
という表現を与えることにした。

さらに、『変数』という文脈に限り、これらにかみ砕いた解釈を与えると、
「nullとは、変数に値が定義されていない状態のこと」
「普通の状態とは、変数に何かしらの値が定義されている状態のこと」
ということができる。

以上

閲覧者諸氏、先輩方によりご指摘ご意見を頂ければ幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

勉強する気力がびっくりするくらい湧かないしWordPressでアフィブログ作ろうと思った話

前回の記事(これ)書いてから満足して一向に学習意欲が湧かないのでWordPressでお小遣い稼ごうと思った話です。
こんな感じでWordPressのサイト作るんや~程度の備忘録的なやつです。この記事だけで網羅できてないんでその辺は適当にググりながらやるといいと思います。

一応できたやつ→なかむらのブログです

この記事について

そもそも勉強するのもお金稼げるようになりたいからだしアフィブログ作るのもええんでないかって安直な考えで手を出しました。

結論だけ先に書いておくとなんとなくWordPressってやつが簡単らしい程度の知識でブログ作ったらお金も時間も思ったよりかかってビビったのでアフィやる人は普通にブログサービスを使えばいいと思います。

まあWordPressってこんなものなのか~って勉強にはなったと思います。まったく触ったことないです><ってよりは多少経験があるほうがまあいいんじゃないでしょうか。
認識が間違ってなければMVCモデル"風"のサイトが簡単にできるパッケージがWordPress。。。なんですよね?どうも完全にMVCモデルっては言えないみたいなことがインターネットに書いてありました。難しい話はよくわかりません。

まだアフィ貼ってないですけどアフィとか嫌いな人とかはスルーしてください。

やったこと

レンタルサーバー借りるの巻

おすすめ 安い レンタルサーバーみたいな感じでググったら出てきたのでスターサーバー(りんく)にしました。
Netowlって会社のアカウント作って決済情報登録して利用申し込みしたら一瞬で借りられました。
確か月額250円のプランにしたんですけど最初は無料プランでもいい気がします。スターサーバーの無料プランがいいのかは知りません。ググってください。

ドメイン取得するの巻

いきなり順番ミスってたみたいでドメインを先に取得したほうがいいみたいです。
ドメイン申請してから実際に取得できるまで時間がかかるみたいでよくわかんない画面が出てきて心が折れかけます。ぼーっと待ってても解決しそうになかったのでググったらおとなしく待てって書いてあったのでその日は寝ました。
image.png

たぶんドメインは前もって準備しておくべきだと思います。結構お金もかかるし。。。(1年で1000円ちょっとだったような気がします。)
聞いたことはあったのでお名前ドットコム(りんく)でドメイン取得しました。
whois情報公開代行でググっておくと幸せになれると思います。難しいことはよくわかりません。

ドメインを設定するの巻

ドメインを取得しただけではなんの意味もないらしく、そのドメインでどのサーバーを見に行くのか的な設定が必要みたいです。
最初にお名前ドットコム側で設定してそのあとスターサーバー側で設定したらよくわからないうちにできました。XXサーバー ドメイン設定 とかでググると先人の知恵がたくさん出てくると思います。

WordPress入れるの巻

ここまでやってやっとWordPressが出てきます。メールアドレスとパスワード入力したら勝手にブログできておしまい!だと思っててごめんなさい。

最初スターサーバーから適当なアドレスもらえたんでそこにWordPress入れて満足してたんですけどどうもドメインくっつけたらそっちに入れなきゃダメみたいですね。
あとググるとホームディレクトリ/wpにインストールやで~って書いてるサイトもあるんですけど罠です。それやると後々めんどいと思います。やめましょう。(オンプレの社内サーバとかに入れるならそれでもいいと思います)



眠いのでWordPressをインストールしてからの話はこの土日のどこかで書こうと思います。
では。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Webサービスの企画、開発、公開まで全部ひとりでやってみた話

先日、ひとり旅のための宿検索サイト「ソロ旅ねっと」というサービスを公開しました。

ソロ旅ねっと

ソロ旅ねっとは、複数地域、複数の宿泊予定日を自由に組み合わせて、一人宿泊が可能な旅館、ホテルを検索できるサービスです。
「どこかの金曜日に有給を取って北の方の温泉地に泊りでで行きたい」、みたいな条件で、旅館、ホテルを簡単に検索できるようなサービスを目指しています。

このサービスをまじめに考えだしたのは2018年の12月初旬で、ソースを書き始めたのは同年12月の下旬頃です。
ソースコードの最初のコミットから3か月、最初のリリースからも約2か月が経ったので、これまでを振り返りつつ、宣伝もかねて、今回は、サービスを作ろうと思った経緯、サービスの中身の話などを、サービスの紹介と合わせてお話ししたいと思います。

なぜ作ろうと思ったか

僕は割と一人での旅行(特に温泉地)が好きで、年に数回、どこかの温泉地に赴き、1~2泊で、ひたすらダラダラするのを生きがいの一つとしております。
泊りで行くので宿泊場所は事前に取らなきゃアカンのですが、既存の宿泊施設検索サイトで宿探しをするのはとてもとても使いづらい&面倒くさいのです。
そこで、僕が使いやすいサービスを作ってみようと思ったのがきっかけです。

僕の使い方だと、今ある宿検索サイト全部がとてもとても使いづらい&宿探しが面倒くさい

「来週か再来週あたりの金曜日に、北の方の温泉地に行ってみたい」という条件で、宿泊施設を探そうとすると、既存の宿検索サイトはとんでもなく使いづらいです。

宿泊施設検索サイトは、楽天トラベル、じゃらん、JTB、など、いくつもありますが、どのサイトも目的地をきちんと入力しないと検索できないようになっております。
しかも、「北の方にある温泉地」などという曖昧な表現ではだめで、○○県××市、だとか ○○温泉、などという感じで目的地をかなり正確に限定する必要があります。

なぜ、こういう仕様なのか

僕は旅館・ホテル検索サービスを運営しているようなところで働いた経験がないので完全な憶測になりますが、そのようなサイト設計になっている原因はいくつか推測できます。

そういう需要はそもそも無い

検索サービスに入ってくる人の大半は、観光で行きたい場所などの目的地は完全に決まっている。
この場合、わざわざ広範囲での宿泊施設検索を用意する必要はありません。

システム設計の都合

内部管理している宿泊施設データが、地域をキーとして検索されることを前提として設計されている。
複数地域をまたいだ検索を実装した場合、クエリーが複雑になったり、サーバに負荷がかかったり、十分な応答性能が出せない可能性があり、簡単に実装することができない。
サービス公開後のシステム設計の変更ってとんでもなく大変なのです。

いい感じのUI/UXが思いつかない、もしくは実現が難しい

大雑把な地域でも細かい地域でも検索できる、見栄えが良く、使い勝手の良いUI/UXを提供するのは確かに難しいと思います。
複数の地域を色々選べるようにしても、エンドユーザさんが使いこなせなかったり、条件指定がめんどくさくて離脱してしまっては元も子もありません。

地域ごとに設定されている広告枠や検索結果上位表示枠の都合

宿泊施設から掲載料とは別にお金をもらって、地域ページのサイドバーに「おすすめの宿泊施設」として特定の施設を常時表示させたり(広告)、お金をたくさん支払ってくれた宿泊施設を検索結果の上位に表示させたりといった施策がとられていることもあると思います。
しかし、それゆえに複数地域をまたいだ検索コンテンツは提供しづらい(サイドバーのおすすめに何を出すか、表示順位をどうするかなどの問題)。

SEOがらみの都合

この辺あまり詳しくないのですが、サイトトップ > 都道府県 > 市区町村 > ホテル一覧 みたいなきれいな構造になっていた方がSEO上有利、なのかもしれません。
ただ、エンドユーザさんの使い勝手を犠牲にしてでも、検索エンジンには気を使うという設計方針が選ばれているんだとしたら少し残念と感じます。

自分の望む形のものがないならば・・・

いよいよ年末の2018年の12月初旬、お正月明けの温泉旅行プランを妄想しつつ、使いづらいと思いながらも楽天トラベルで宿検索をしておりました。その時に、作れそうなら、自分が使いやすいと思うサービスを作ってみてもいいかな、と思い、調査を始めました。

実現手段を考える

楽天が、開発者向けに楽天市場の商品検索APIを公開しているのは知っていたので、楽天トラベルの情報もとれるのではないかと思い、調べてみました。
楽天Webサービス:API一覧
ドキュメントを確認したところ、楽天トラベルの施設検索、空室検索もAPIとして提供されていました。
そこで、今回はこちらを利用させていただいて、一人旅専用の旅館、ホテルの検索サービスを作ってみることにしました。
なお、あとで知ったのですが、同様のサービスがじゃらんからも提供されているようです。

要件定義

サイトにどんな機能を盛り込むか

楽天が提供しているAPIを利用させていただくため、楽天が提供していない機能、規約違反になってしまうような機能は提供できません。
それを踏まえたうえで、APIドキュメントを読みつつ、どれくらいのことができそうかを決めていきます。

できそうなこと

  • 複数地域をまたいだ一人で泊まれる旅館・ホテルの検索
    • 1回のAPI呼び出しで取得できるのは、1つの地域の宿泊施設の結果のみ。
      • 事前に全施設の情報を取得して、ソロ旅ねっと管理のデータベースに蓄積。
      • エンドユーザさんが検索したら、楽天にクエリーを投げるのではなく、 ソロ旅ねっとのデータベースに問い合わせを行う。
  • 駅近く、温泉宿などでの絞り込み条件
    • 温泉付き施設、朝食付きプランあり、夕食付プランあり、禁煙部屋の有り無し、といった絞り込み条件は APIで提供されています。
    • また、鉄道駅が近くにあるか、という情報は、緯度経度付きの駅データを別途用意できれば実現可能
    • 楽天トラベルの宿泊施設情報には、緯度経度データも付与されている
  • 旅館、ホテルが提供しているプラン、価格を表示
    • APIで、宿泊プラン(最大3件)、プランごとの価格情報は取得できるようになっている。
    • ただ、最大3件までしか取得できないため、全プラン&それぞれの価格を提示することは不可能。
    • 同じプランでも土日祝日などは少し高めの値段を設定している宿泊施設もそれなりにあるのですが、その情報をちゃんと取得できるようになっている。えらい。
  • 当日から数えて1か月程度の空室状況の確認
    • API単発の呼び出しでは、〇月〇日に大人1人で宿泊可能な、○○(地域、緯度経度半径xキロ以内 など)に存在する宿泊施設を検索ということしかできない
    • 複数の宿泊日での検索を行うためには、APIで事前にクロール&データ取得しておく必要がある。
    • 空室状況のデータは生ものなので、ある程度の頻度で常に更新しないといけない。
  • 検索結果ページからの楽天トラベルの宿泊施設ページへのアフィリエイトリンク
    • こちらは、APIで容易に取得できるようになっている

実現できそうにないこと

  • 宿泊人数を自由に指定して検索できるようにする
    • APIとして提供されている機能の制限、時間当たりに呼び出せるAPIの回数などの制限のため難しい
  • 楽天が提供しているすべての絞り込み条件に対応する
    • APIの検索条件としては利用できるのですが、API戻り値の仕様や、時間当たりに呼び出せるAPIの回数などの制限のため難しい
    • 僕が絶対はずしたくなかった、夕食付プラン、温泉付き施設の2つと、別途用意した駅データを利用した駅近くの施設、の3つの絞り込み条件に対応することにした
  • 駅近くの宿泊施設の場合、最寄り駅の時刻表サイトや、路線検索サイトへのリンクを張る
    • APIの利用規約に、「APIを利用したページから楽天以外のサイトにリンクしてはならない」という利用規約があるため不可能。
    • おそらく、楽天以外の予約サイトに飛ばしたり、amazonなどの競合他社サイトへの流出を抑制したいという意図があるのだと思いますが、ここは非常に残念なところ。
    • そのため、アドセンス広告なども貼れない。悲しい。
  • 施設周辺の地図を出したい
    • google map APIの利用が有料化され、しかも結構なお値段がするので断念。

「できそうなこと」でも書いていますが、このサービスを実現するには、宿泊施設の情報、空室状況を、常に更新していく必要があります。そして、それを実現するには結構な回数のAPIコールが必要です。
例えば、空室状況の更新を10日に1回とした場合、データ取得&検索タイミングによっては、すでに予約でいっぱいな施設だらけになってしまうかもしれません。

最終的には、

  • どれくらい先までの空室状況を取得したいか
  • 空室状況の鮮度はどれくらいにするか
  • 検索条件として指定できるオプションで外したくないものはどれか
  • DBに保存するデータ量はどのくらいになるか
  • 現実的なAPI呼び出し回数で実現可能か
  • 運用費用(サーバ費用)はどんなもんになるか

などを考えつつ、システム仕様に落とし込んでいきます。

ちなみに、ソロ旅ねっとでは、28日後までの空室状況を1日~1日半程度の時間をかけて取得、更新をしています。
本当は、30日分の宿泊可能な施設情報を1日以内に取得したかったのですが、性能的に一歩及ばず、今後の課題になっています。

なお、楽天トラベルに登録されている一人宿泊が可能な宿泊施設は1万~2万ほどです(事前に1回クロールして調べた)
これを踏まえると、各施設に設定されているプランの空室状況を表すテーブルのレコード数は100万以上になる可能性があります。
宿泊施設データ(約1万~2万)はともかく、空室状況データの100万レコードを1つのテーブルに格納するのは多少サーバにお金をかけないと厳しいかもと思ったので、空室状況テーブルのデータはパーティショニングした方がよさそうです。

開発言語、利用技術のの選定

要件が固まってきたので、言語は何にするか、DBはどうするかということの検討に移ります。

  • DBの選定
    • MySQLは嫌いなので候補から除外
    • ElasticSearchは、低スぺサーバーでアプリと一緒に動かすのは多分無謀すぎるのでこれも除外
    • 割と消去法ですが、DBはpostgreSQLに決定
      • バージョンは9.6か10系にする予定でしたが、上で少し書いた通り、hashパーティショニングの機能が欲しかったため11に決定
    • PostgreSQL11の難点が1つ。Windowsから安定してつながるクライアントアプリがない。
      • pgAdmin3が完全サポート外(一応つながるけど、エラーがバンバン出る)。
      • 今は、VisualStudio codeのプラグイン[ms-ossdata.vscode-postgresql] を利用。
        • テーブル一覧などの機能はないが、クエリー投げて結果をテーブル表示する程度の用途であれば使いやすい。
  • 開発言語の選定
    • Java
      • JVMってメモリー食いそう
      • 前々職の天才中国人エンジニアが作ったasta4dというフレームワークを使おうかとも思ったけど、割とキャッシュ前提のつくりなので、低スぺサーバーで動かすにはちょっと不安
    • PHP
      • 現職で使ってるけど、とにかく楽。
      • 人をダメにする開発言語なんじゃないかって思うくらいとにかく楽。
      • よく言えば、アルゴリズム以外で詰まることが何もない。
    • Ruby
      • 昔は好きだったけどRailsで嫌いになった。
        • 書いていてあんま楽しくなかったため。
      • でも slim(テンプレートエンジン)は好き。
      • 書いてて楽しくないフレームワークをわざわざ選択する気はない。
    • Goとか、Rustとか
      • 勉強しながら作るのも楽しいのですが、今回はそれよりも早く作ってサービス公開したい
      • お作法などがわかってきたらPHPから乗り換えるかも
    • 最終的にはPHPを選択
      • 実装開始から公開まで最短で進めたかったため

どれだけのお金がかかるか

利用規約に、「一般に公開されていないサイトでの利用は不可」との記述があるため、僕専用サービスとして、ずっとlocalhostで動かし続けるわけにはいきません。
また、収益化できているというのも、開発モチベーションとしてはとても大事なことです。

現状の収益化手段は、楽天アフィリエイトプログラムです。
運よく利用者が現れて、サイト経由で予約が成立すれば、楽天アフィリエイトプログラムにより収益が発生するようになっています。
が、現状では、需要があるか、人が来るか等、まったくわからないため、コストはできる限り抑えたいです。
とはいえ、ある程度のレスポンス速度はやっぱり必要なので、その辺のバランスを考えて、ソロ旅ねっとは以下のような構成で運用しています。

  • ドメイン管理
    • お名前.com
      • 年間1000円程度
  • サーバー
    • AWS
      • ec2 instance
        • 米国バージニア州 t3-micro 3年物Reserved instance
          • 日本から接続した場合、東京リージョンよりも若干レスポンスに時間がかかるという欠点はありますが、東京リージョンよりも安いです。
        • ubuntu 18.04
          • 利用したいミドルウェア(Postgres11)のパッケージが用意されていなかったため、amazon linuxは候補から除外。
        • Webはnginx/php7.2
        • DBはpostgresql 11(RDSを立てるということはせず、1つのインスタンスにWebとDBを共存させています。理由はもちろん費用を抑えるため)
      • この構成で3年間で140ドルほど
        • ec2-instance の費用が3年間で110ドル。ほかにebsの費用が1日3セントほど。データ転送の費用は別途。

サービス運営に直接かかった費用だけを考えれば、損益分岐点は3年で1万5千円~1万8千円程度となります。
予約1件あたりの収益を100円(楽天アフィリエイトの収益は、予約金額の1%)程度で計算しても、少なくとも送客数150人から180人は必要です。
過疎ったら確実に達成できない。過疎らなくても難易度は割とハードな気がします。
少なくとも、確定申告が必要になるくらい稼ぐのは難しそう。
自分が欲しいからという動機づけがなければ、この時点で計画倒れとなっていたと思います。

サイト名をどうするか

gitリポジトリ名をどうするか、という問題もあったため、サイト名は最初に決めました。
名前を決めるために考えたことは以下の4つです。

  • 言いやすく、覚えやすいこと
  • ドメインが取られていないこと
  • 同名のサービスが存在しないこと
  • 商標登録されていないこと

特に商標は、権利者がいた場合とんでもなく面倒くさいことになりそうな気もしますし、事前に確認するのは大事だと思います。

実装開始から公開まで

gitリポジトリへの最初のcommitが2018年の12月20日、1stリリースが2019年1月27日なので、開発期間は1か月ちょっとでした。開発は、会社の昼休み、平日帰宅後にすこし、休日予定がなかった時に進めていました。
業務時間中も、どんな感じで実装していこうかっていう妄想くらいはしていたかも。

サーバ側の実装に関して

サーバ側の実装に関しては、今更困るようなことは特にありませんでした。
slim(フレームワーク)を使おうかとも思ったけど、完全に理解しているわけでもないし、ハマった時の調査とか面倒くさかったので、お手製のMVCフレームワークもどきを作成&使用しています。
なお、外部のライブラリ、モジュールを全く使っていないわけではなく、例えば、template engine として twig を利用しております。
DB接続まわりについては、PDOを直接利用することにしました。Lalavel等を組み入れてもよかったのですが、slimと同様の理由で使用していません。

画面デザイン

デザインセンスがあるわけでもなく、cssにさほど詳しいわけでもなかったため、ここはかなり試行錯誤で進めていました。

  • 最低限の見た目は担保
    • 初回リリースは、いかにもbootstrapで作りました的なサイト。
    • 12分割グリッドは使いやすいようで細かい制御はやりずらい、等、様々な理由により、初回リリース後の機能拡張、デザイン変更、などのフェーズで徐々に依存度は下がってます。
  • 旧式ブラウザ対応で苦労はしたくない
    • cssであまりトリッキーなこととか難しいことはやりたくない
      • Firefoxとchromeで意図通りに見られて、Edge最新版でもとりあえずは不自由なく見られればOKとしました。
    • 最初のリリースでは、IE11でもとりあえず見られる形にはなっていたんだけど、現在公開されているバージョンでは表示が乱れまくっています。
      • 旧世代IEでの表示確認は1度もやってません
    • flexboxが神過ぎる。
      • flexboxが存在しなかった時代、デザイナーはどうやって横並びのコンテンツをきれいに配置していたのか全く分からない
      • float: left なんですかそれ、いまだにさっぱりわからないし、特に覚える気もないです
  • 画面レイアウト、デザイン設計は基本だけは押さえる
    • サイトのデザインは以下の5点だけ気を付けました
    • 色を使いすぎない
      • 最初のリリース時は結構ごてごてしてたけど今は3色+白+黒に抑えています。
      • メインカラー(緑系)+アクセントカラー(メインカラーの反対色)+補助色(青)
      • メインカラーの緑はなんとなく決めた
      • カレンダー表示で、土曜日(青)、日曜日(赤)を使っていたので、それををそのままアクセントカラー、補助色として採用
        • アクセントカラーとして赤色、リンクなどで利用する色として青を割り当て
      • 色コードは、最初はマテリアルデザインの標準カラーを適当に選んで使用していましたが、現在は日本の伝統色 和色大辞典というサイトに載っている色から、自分の気に入った色を選んで使用しています。
    • 余白を適切にとる
      • これは特に説明の必要ないかもしれませんが、適切に行間を設けるだとか、各コンテンツ間に適切な余白を入れる等のことです。
    • 余白の大きさは統一する
      • 例えば「3つ横並びのコンテンツ」があったとき1つ目と2つ目の隙間は15px、2つ目と3つ目の隙間は18px のようなことはせず、ページ全体を通して、余白のサイズはなるべくそろえています。
    • テキストの開始位置(右詰めの場合は終了位置)をそろえる
      • タイトル+リード文みたいなリストがあったとき、リード文部分は16px下げる、みたいなことを僕もよくやっていたのですが、端をそろえた方が、安定した感じになり、見た目も綺麗になります。
    • borderを使いすぎない。その代わり、コンテンツの境目は色の違いで表現する。
      • 現在のデザインでもカレンダー部分や一部のボタンでborder を使っていますが、ごちゃごちゃしてしまうので、極力使わないようにしています。
    • デザインについては、前々職のデザイン社内勉強会で聞いた「見た目最低のパワポプレゼンをいい感じに改善する手法」のという話がとても参考になっています。
    • 大体同様の内容が、やってはいけないデザイン という書籍にとても丁寧に書かれています(勉強会の人と本の著者は全然別の人です。念のため)。
  • まじめな遊び心ということで、他のサイトではあまり見かけないデザインも取り入れてみる
    • せっかくのオレオレサービスなので、少し変わったこともやってみました。
      • ページネーション、検索結果ヘッダ部分(〇ページ目/〇件の結果中)の部分は、画面をスクロールさせても常に表示されるようにしています。
      • あまり深い意図があったわけではなく、なんとなく、他のサイトと差別化したかったから。
      • 圧迫感が出ないような調整をするのは結構大変でした。
  • 課題
    • スマホで見ると文字が小さい。タップ領域も小さいので操作性も悪い。
    • サーチコンソールにも指摘されている。

そしてサービス公開

サービスを公開したのは、金曜日深夜(土曜日早朝近く)、仕事では絶対に選びたくない曜日&時間でした。
割とぎりぎりまでコードを書いていて、公開直前に、awsのインスタンスの購入やドメイン取得&設定を行いました。
この時点まで、Linux環境で全く動かしていなかった(Windowsのローカル環境使ってました)ため、ハマったらその日の公開はとりあえず諦めるつもりでいましたが、特にトラブルもなく、無事に公開までこぎつけることができました。

公開からこれまで

サービスの公開以降は、ユーザさんの反応やGAなどを確認しつつ、改善していくのがセオリーだと思うのですが、PVが全然ないし、自分が作りたいと思ったこともまだまだできていないので、現在は、その辺の実装もやりつつ、最低限の環境整備的なことをやっています。

機能追加、性能改善以外では、以下のようなことをやっていました。

テスト環境の準備

さすがにテスト環境も必要だと思い、本公開後に準備しました。
といっても、テスト時だけ立ち上がるinstanceなどを用意したわけではなく、本番環境のport8080がテスト環境になっています。
会社で同じことやったら、方々からアホといわれること間違いなしです。

デプロイ手順の簡略化

初回リリース直後は、毎回WinSCPを立ち上げてファイルのコピーというとても残念な運用をしていました。
さすがにそれはやめましたが、今でも割と残念な運用をしています。
CI使って、テストにpassしたらデプロイするとかの仕組みを作るのが割と当たり前なんでしょうけど、個人で作ったオレオレサービスだし、いろいろ設定するのも面倒くさい、とはいえ scpで毎回アップロードするのも面倒くさいので、rsyncするだけのスクリプトを組んで、リリース時はそれを流しています。

deploy.sh
#!/bin/bash

cp .key/solotabiproduction.pem ~/
chmod 0600 ~/solotabiproduction.pem
composer update
rsync -arvz --exclude 'composer.*' --exclude='.*' --exclude '*.bat' --exclude='environment' --exclude '*.sh' --exclude 'cache' --delete --partial --progress -e "ssh -i ~/solotabiproduction.pem" ./ ubuntu@ec2-**-**-**-**.compute-1.amazonaws.com:~/webroot/
rm ~/solotabiproduction.pem

開発環境はWindowsなので、別途以下のような deploy.batを用意し、実際のリリース時にはこちらのバッチをたたいています

deploy.bat
wsl bash ./deploy.sh

お手軽ですが、このやり方ではリリース中にサーバのソースファイルが中途半端な状態になり、更新中にサイトが500になる可能性が非常に高いです。
instanceをRoute53にぶら下げて、リリース時に向き先のインスタンスを切り替えるとか、サーバの別ディレクトリに全ファイルをアップロードし、サーバ側でリネームする、などで、ダウンタイムをなくす or 減らすことはできますが、そういうのは人がたくさん来るようになったら考えることにしています。

なお、stage.batというバッチファイルもあり、これを使えば(以下略

今やってること

  • 都道府県よりももう少し細かい範囲での地域検索
    • UIをどうするかで悩み中
  • Aタグで検索結果ページに遷移する導線が全くないので、一応それくらいは用意しようかと(SEO)

総括

  • 技術的な裏付けができていて、細かい部分にあまり神経質にならなければ、サービス開発&リリースは意外と簡単
  • ただし、収益的に成功する可能性のあるサービスを企画するのは大変

ソロ旅ねっと

力尽きたので、この辺で終了です。

もうちょい内部の話とか、PHP製のなんちゃってMVCフレームワークの話とか、気が向いたら書くかもしれません。

それでは、ごきげんよう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む