アナログCPU:5108843109

ゲームと音楽とプログラミング(酒と女とロックンロールのノリで)

('ω') < イザユケエンジニャー

Laravel触ってみた

環境はざっくり↓こんなん
Windows×XAMPP(ApacheMySQL/MariaDB×PHP

自分のスキルの前提としては

  • 本職はWindowsServer×Apache×SQLServer×PHP(CodeIgniter)
  • DBについてはMySQLの方が経験長い
  • FWはZendベースの自社FWの経験が長かった
  • Cake、Fuelあたりも経験あり、あまり好きじゃないタイプだった
  • Laravelも一瞬触ったがなんか肌に合わず挫折した経験あり、実質未知の世界

という感じ。

CodeIgniter個人的にはわかりやすくて超好きなんですが
Laravelが人気なのは知ってるしユーザーが多いことのメリットもわかってるつもりだし、
なにより挫折したままなのは気に食わないので、やる。

他FWに比べると処理速度が懸念点といえばそうだけど、
まあ別に大量の細かいアクセスを捌く系のシステムでないならひとまずは気にしなくていいレベルかなとは思ってる。
Phalconも好きだよ。速いしかっこいいし。

自分用の覚書?作業記録?みたいな記事なので、知ってることに関してはそんなに書かない。
あと、触って覚えるタイプの人間なので、まず調べず触るところからやってる部分もある。
ということでもしこれを参考にしようとしている人がいたら、あてにしすぎないでください。
あとめんどくさいのでスクショで済ませてる部分が多く、コピペにも向かないです。

はいスタート。

準備

  • 以下をインストールする
    • XAMPP
    • Composer
    • Laravel
  • 諸々調整して、Laravelのスタートページが出てくる状態にする

やり方は自分の過去記事を参考にしつつ。
複数プロジェクトの開発環境構築 - アナログCPU:5108843109
Windows×nginx×PHP8×Laravel ローカル環境構築してみる - アナログCPU:5108843109

まあここは本題じゃないのでどうでもいい。

ディレクトリ構造を把握する

マジで何もかもわからないところからスタートなんで、まずはデフォルトのディレクトリ構造についてググる

  • app
    • だいたいのコードはここに書くらしい
  • bootstrap
    • 初期化用の諸々 autoloadとか
  • config
    • 名前のとおり、設定ファイルとか置く
  • database
    • 名前のとおりDB関連の諸々を置く…っぽいがいまいち分かっていない .envに接続設定書く(※後述)だけじゃアカンのか?
  • lang
    • 言語情報用。多言語対応サイトでもないと使う必要がない気はする
  • public
    • 公開ディレクト
    • 最初に実行されるindex.phpとか、画像とかCSSとかJSとかはここ
  • resources
  • routes
    • ルーティング用の設定を置くところっぽい。
  • storage
    • キャッシュファイルなどがここに入るらしい。あとは「ユーザーがアップロードしたファイル」なんかもここっぽい。
  • tests
    • テストコードを置くところ。本番環境には置かないディレクトリってこと?
  • vendor
    • Composerの依存内容を置くらしい。Composerについてもよくわかってないので未知すぎる
    • 本番環境には置かなくていいのかなと思ったけど、autoload.phpがここにあったので必要だった。

Laravelのスタートページを移動させる

Laravelの新規プロジェクトを作った直後がこの状態。

f:id:honey8823:20220210215521p:plain

バージョン9なんだ~、と何気なく調べたらかなり直近のリリースだったのか。
(これ書いてるのが2022/02/10、リリースが2022/02/08っぽい)
Laravel 9 Upgrade Memo

まあそれはともかくとして。
これはなんかの実装サンプルになるかもしれないけどここに居座られても困るので、ちょっと別の場所に移動してもらおうと思います。
どうやって表示してんのかな? と public/index.phpから順に追う…のは面倒そうだったので、
逆にviewレベルから見てみることに。
試しにこの英文の一部でgrepかけてみると、viewファイルらしきもの見つかりました。
resources\views\welcome.blade.php
あと、
storage\framework\views\0e9b7b4…74ed85a.php
みたいなファイルも見つかりました。
どうやら、controllerやview的な諸々からコンパイルしたもの?というかキャッシュファイル的なもの?をstorageに置いてるっぽいですね。

それはともかくviewファイルですが、
軽く調べたところ、LaravelにはデフォルトでBladeというテンプレートエンジンが乗っかっていて、それで書かれてますね。
f:id:honey8823:20220210220652p:plain:w400
おお~~わかりやすい。ある程度はこれ真似するだけでも書けそうじゃん。

で、このviewを呼んでるのはどこかな?ということで「welcome」でgrepかけてみると、
routes\web.php
内にありました。ルーティングですね。

Route::get('/', function () {
    return view('welcome');
});

ほ~。
じゃあこのwelcomeページは別URLによけておこう。

Route::get('/sample', function () {
    return view('welcome');
});

はいオッケー。わかりやすいじゃん。
これで、「/」だと404になり、「/sample」で先ほどのページが表示されるようになりました。

けどちょっと思ってたのと違ったというか。
知りたかったのは「特定のController呼び出して、処理の結果をviewに渡す」みたいな部分だったというか…。
ルーティングで直接view返すの⁉っていうのが衝撃でした。
普段使ってるCodeIgniterだと、必ずController経由することになるので。

で、そのへんのサンプルはないみたいなので、ぐぐってきました。
Laravelのルーティングの書き方を10分でサクッと学ぶ | Web Apps Labo
Laravelのルーティング(Routing)のまとめ! | codelikeなブログ
Laravel8でのルーティングで、コントローラーの指定の仕方4選 - Qiita

いや~待って ちょっとおっさん一気に覚えらんない 書き方のクセがでかい
ひとまずは

  • web.phpapi.php の2種類がある
    • 画面で動かすやつはweb.php
    • SPAな実装する場合とか、外部から叩いてもらうようなAPIの場合はapi.php
  • viewや値などを直接返す方法と、Controllerを呼び出す方法がある
  • Laravel7以前と8以降で書き方違うので注意

…という感じですね。

で、今回使ってるLaravelは9なので新しい書き方でいく必要があり、
先にルーティングするの難易度高そうなので、まずControllerを実際に作ってみます。

Controllerを作ってみる


…いや、どこにどう作るんだコレ?

またぐぐった結果、
コマンドプロンプト

cd プロジェクトのディレクトphp artisan  make:controller HogeController

を実行
だそうです。
えっコントローラ作るのに毎回コマンド打つ…んですか…? ほんとに?

f:id:honey8823:20220210230034p:plain
f:id:honey8823:20220210230106p:plain
ほんとにできた。

お試しでHelloWorldするだけのメソッドを設置。
f:id:honey8823:20220210231347p:plain

で、ルーティングに戻ります。
app\Http\Controllers\IndexController.php の index()なので、

Route::get('/', 'App\Http\Controllers\IndexController@index');

をweb.phpに追記してみました。

f:id:honey8823:20220210231837p:plain
成功です。

Controllerからviewに値を渡して表示してもらう

じゃあ次はControllerでいろいろごにょごにょ処理して、それをviewに渡し、表示してもらうやつ。
といってもこれはさほど難しくはなさそう。
Laravel controllerからViewへ値(変数)を渡す

↓Controller
f:id:honey8823:20220210233805p:plain

↓View(新しく作った)
f:id:honey8823:20220210233829p:plain

↓結果
f:id:honey8823:20220210233856p:plain

HTMLタグのエスケープ勝手にやってくれるの優秀ですね…しかもやりすぎてもない(inputタグの中とか)。

DBにアクセスし、テーブルの中身を取ってきて表示する

まずテーブル作って適当にデータ入れておきます。詳しくは省略。

Laravel側は、まず接続設定。
.envの中の↓を調整します。
f:id:honey8823:20220210235053p:plain
今回はローカル環境ということでテーブル名だけ変更して終わり。

次、Controllerの中でSELECTしてくる処理を書きます。
f:id:honey8823:20220210235619p:plain

最後、それをViewでもにょもにょします。
f:id:honey8823:20220210235641p:plain

いや~そんな
こんな少ないわけないし、ぐぐりながら10分で書いたやつが一発で動くわけないじゃ~ん
f:id:honey8823:20220210235744p:plain

動いた!?
動きました。ここまでできれば勝ったも同然ですね。

とりあえずここまで

あとは細かいところぐぐりながらいけばなんとかなりそうってレベルな気がします。
昔速攻で挫折したのどこだろう。ルーティングかな。

Windows×nginx×PHP8×Laravel ローカル環境構築してみる

いろいろお試し~。

nginx

基本

  • ダウンロード
  • 任意のディレクトリに設置
    • 今回は C:\nginx とした(この直下に nginx.exe が来る)
  • 設定ファイルを編集
    • C:\nginx\conf\nginx.conf
    • ひとまずポート番号を必要に応じて書き換え
      • 【※1】の表記のうち、コメントアウトされていない行が対象
      • 他アプリやXAMPPとの共存を考慮して、今回は「8081」とした
  • 動作確認

複数のプロジェクトを開発できるように対応

  • 設定変更
    • 再度 nginx.conf を開く
    • 先ほど編集した行【※1】を含む「server { ... }」全体をコメントアウトする
    • 代わりに【※4】の記述を追加
    • 設定したserver_nameの記述に合わせてhostsを設定【※5】
  • 動くかどうか確認する
    • 設定したrootのディレクトリに適当なindex.htmlを設置
    • nginxを開始する
    • ブラウザで、設定したURLにアクセス
    • nginxを終了する

補足類

【※1】
↓の「80」の部分を書き替える

listen       80;

【※2】

cd c:\nginx
start nginx

【※3】

nginx -s stop

【※4】

##### このかたまりでプロジェクト単位。
##### 複数用意するときはこれを複数設置して適宜調整する
server {
    listen       8081;
    server_name  testproject.localhost;
    root   C:/dev/testproject;
    index  index.php index.html index.htm;
}

【※5】

127.0.0.1       testproject.localhost

PHP

  • ダウンロード
  • 任意のディレクトリに設置する
    • 今回は C:\php8 とした(この直下に php.exe が来る)
  • 環境変数(Path)に上記ディレクトリを追加する
  • 設定ファイルを作成する
    • C:\php8\php.ini-development をコピーして C:\php8\php.ini とする
  • 設定ファイルを調整する
    • 「extension=fileinfo」がコメントアウトされていれば外す(存在しなければ追記する)(Laravelを動かすのに必要っぽい)
  • nginx側の設定を調整する
    • nginx.confを開き、先程追加した「server{ ... }」内に【※1】の内容を追記
  • 動くかどうか確認する

補足類

【※1】

#### PHPの設定
# 正規表現、パスが「xxxx.php」や「aaa/xxxx.php」や「abc/xxxx.php/bbbb」などに一致
location ~ [^/]\.php(/|$) {
    # $fastcgi_path_info の値をキャプチャする正規表現を定義
    # 一つ目の()が $fastcgi_script_name の値になり、二つ目は $fastcgi_path_info の値になる
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;

    # $document_root ルートディレクトリで設定したパス
    # $fastcgi_script_name ファイル名のパス
    # -f はファイルが存在するかの判定
    # ファイルがなければ404エラーを返す
    if (!-f $document_root$fastcgi_script_name) {
        return 404;
    }

    # phpへアクセスするためのIPアドレスとポートの設定
    fastcgi_pass   127.0.0.1:9000;
    # phpでのindexファイル名を設定、
    # URLが「/」で終わってるものに対してインデックスとして使われるファイル名の指定
    fastcgi_index  index.php;
    #### fastcgi_param に関する設定
    # 多数のfastcgi_paramsの設定が書いてあるfastcgi_paramsファイルを読み込む
    include        fastcgi_params;
    # 「HTTP_PROXY」パラメータを空にする、HTTPProxyに関する脆弱性を和らげる
    fastcgi_param  HTTP_PROXY "";
    # 「SCRIPT_FILENAME」パラメータはphp-fpmがスクリプト名を決定するための設定
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
}

Composer

Laravel使うならComposerが必須?っぽい?
ComposerはPHP向けの管理ソフトで、アプリやライブラリの依存関係などを管理しているやつ。

  • ダウンロード・インストール
  • インストールされているか確認する

Laravel

  • ダウンロード・インストール
  • インストールされているか確認する
  • プロジェクトを作
  • nginx側の設定を調整する
    • nginx.conf を開き、rootに「/public」を付け加える 例:C:/dev/testproject/public
  • 動くかどうか確認する
    • nginxとPHPを開始する
    • ブラウザでURLにアクセスし、Laravelのスタートページが表示されればOK
    • nginxとPHPを終了する

補足類

【※1】

cd C:\dev
composer create-project laravel/laravel testproject

これで「testprohect」という名前のプロジェクトが生成される。
明示的に↓のようにバージョン名を付けるほうが適切かも(未調査)

composer create-project laravel/laravel testproject--prefer-dist "5.2.*"

その他

開始・終了のバッチ化

XAMPPだとstart/stopワンクリックだったのにめんどくせ~!!
ということでnginxとPHPの開始・終了はバッチファイルにしてみると楽でした。

開始

@ECHO off
REM // ↑これ以降のコマンド全ての実行結果を表示させない

REM // nginx開始
CD C:\nginx
START nginx.exe

REM // php開始
CD C:\php8
START php-cgi.exe -b 127.0.0.1:9000

EXIT

終了

@ECHO off
REM // ↑これ以降のコマンド全ての実行結果を表示させない

REM // nginx終了
CD C:\nginx
nginx.exe -s quit

REM // php終了
Taskkill /im php-cgi.exe

EXIT

AjaxでPOSTしてるはずがGETになる

jQueryAjax使ってAPIをPOSTで叩いてるのに、何故かGETになる。
数時間かかってなんとか解決。

before

$.ajax({
    type: "POST",
    url: "/api/hoge/add/",
    data: { id: 1 },
    dataType : "text"
})
.done(function(data){ ... })
.fail(function(XMLHttpRequest, textStatus, errorThrown){ ... });

after

$.ajax({
    type: "POST",
    url: "/api/hoge/add",
    data: { id: 1 },
    dataType : "text"
})
.done(function(data){ ... })
.fail(function(XMLHttpRequest, textStatus, errorThrown){ ... });

何この間違い探し。
答えはURLの末尾のスラッシュ。消したら通りました。
.htaccessの設定の問題っぽいがそこを掘るよりはこっちかな…。

PHP8×CodeIgniter4 してみる

遊んでみた。
環境はWindows11のローカル環境。

「なんかあったらググる能力はあるがWeb開発詳しくない」くらいの人向け。かもしれない。
PHPは言語、CodeIgniterはPHPフレームワークです。

ダウンロード・インストール

PHP、というかXAMPPはこちら。
現時点では最新が8.1.1でした。
https://www.apachefriends.org/jp/index.html
インストーラのexeをダウンロードして実行、手順に沿って進む。

CodeIgniter4はこちら。
現時点では最新が4.1.7でした。
https://github.com/codeigniter4/CodeIgniter4/releases
zipでダウンロードしたものを適当に展開しておく。

XAMPPの動作確認

まずは最初の動作確認。
XAMPPのコントロールパネルを開いてApacheをStart。
適当なブラウザで「localhost」にアクセスしてなんか開いたらオッケー。
f:id:honey8823:20220118112859p:plain

これは何が起こっているかというと、

localhostにアクセスする

xamppのインストールフォルダ内の「htdocs」にあるindexファイル(ここではindex.php)が呼ばれる

index.phpでは「htdocs/dashboard/」にリダイレクトしている

「htdocs/dashboard/」にあるindexファイル(ここではindex.html)が呼ばれ、ブラウザに表示される

という感じ。

つまり、自分で何か作ってブラウザに表示させるには、作ったものをhtdocsに配置する…
…が定石ではあるし、そう紹介している記事が多い気がしますが。

この記事では、「ローカル環境用のURLを新しく作って、そこにアクセスされた際に何を呼び出すかの調整」でいきます。
htdocsに直接置く形でいいや…って場合は適当に読み替えてください。

URLを考えてhostsに設定する

まあ何でもいい。
ここでは sandbox.localhost とします。

メモ帳などを管理者権限で開き、
C:\Windows\System32\drivers\etc\hosts
を編集します。

最後の行に

127.0.0.1     sandbox.localhost

を付け足せばOK。

f:id:honey8823:20220118121747p:plain

URLが参照する先を設定する

hostsだけ設定しても、「sandbox.localhost」にアクセスしてみても動作は変わらないので、
次はそのURLが向く先を設定します。

XAMPPの apache/conf/httpd.conf を開きます。
コンパネからも可能。
f:id:honey8823:20220118122150p:plain

開いたら末尾に以下のような形で書き加えます。
「sandbox.localhost」の部分(2か所)は決めたURL、
「C:/dev/sandbox/public/」の部分(2か所)はindexファイルを配置するパスを指定します。

# sandbox.localhost
<virtualHost *:80>
    ServerName sandbox.localhost
    DocumentRoot "C:/dev/sandbox/public/"
</virtualHost>

<Directory "C:/dev/sandbox/public/">
    Options Indexes FollowSymLinks Includes ExecCGI
    AllowOverride All
    Require all granted
</Directory>

f:id:honey8823:20220118122443p:plain

保存したら、Apacheの再起動をします。
コンパネから「Stop」→「Start」でOK。
f:id:honey8823:20220118122854p:plain

URLが参照する先を設定する

さて、指定したパスに何もない場合、当然エラーになります。
動作確認用に適当なファイルを置いてみましょう。

f:id:honey8823:20220118123349p:plain

そのまま表示されればOK!!

CodeIgniterと合わせてみる

ここまででひとまずXAMPPの設定はOKなはず。
次はCodeIgniterを組み込んでみます。

先に貼っておくと公式マニュアルはこちら。
http://pneskin2.nekoget.com/codeigniter/4/build/html/intro/

展開したフォルダを開けてみるとこんな感じ。
f:id:honey8823:20220118124242p:plain
indexファイルは public/index.php になりますので、
「さっきパスを決めた C:/dev/sandbox/public/」=「CodeIgniterのpublic」
になるようにします。
つまり、「C:/dev/sandbox/」に一式を突っ込みます。

これで何かしら動くはず…と「sandbox.localhost」にアクセスしてみたものの、エラー。
f:id:honey8823:20220118132451p:plain

「なんかおかしいで」くらいしか分からないわけですが、ログ(writable\logs 以下)と公式マニュアルを見れば一発解決。

拡張機能 intl extension および mbstring extension がインストールされていることが必要となります。

とのこと。
ということでこれらを有効にしていきましょう。

まずphp.iniを開きます。
f:id:honey8823:20220118132854p:plain

intl extension については、

;extension=intl

という表記を探し、行頭の「;」を消せばOK。

mbstring extension については、

extension=mbstring

という表記を探し、行頭に「;」がついていないことを確認。(=何もしなくていい)

またApacheを再起動してアクセスしなおすと、無事にCodeIgniterのチュートリアルページが表示されました。めでたし。
f:id:honey8823:20220118133415p:plain


あとは実装して遊ぶだけなんですけど、それ書くと長くなりすぎるのでひとまずここまで。

10日間でアンソロ1冊作った話

※もうちょっとまともに作った話はこちら。
honey8823.hateblo.jp


今回は、2021年の年末のラスト10日間でアンソロジーを1冊作った話を。
ついでに言えば金銭的な負担はほぼゼロです。

「そりゃ薄い本作ってみたいけど~、時間もお金もないし~」みたいな言い訳はもう通用しないぞ!みんなも作ろう!!(?)
あと「アンソロの主催とか大変そう~」って言う人もいるけど!「みんなで作ろう!」にすれば何も大変じゃない!!みんなありがとう!!!

◆発端

もう2021年終わっちゃうよ~~、と思いつつ過ごしていた年の瀬、
あるツイートがバズっているのを見かけました。

ほう。

8時間で1冊作る。すげえな。
さすがに再録本とかだと余裕だと思いますが書き下ろしで8時間で1冊。すげえ。そして楽しそう。楽しそうじゃん。
よっしゃ!ワイもなんかやろ!(無駄な行動力)

…(となったのは仕事中だったので、終業から)2時間後…

◆企画の流れ

12/20

20:46 「年内に薄い本なにか作ろうぜ!」というだけの要綱をTwitterに放り投げる。
20:48 わずか2分で最初の1名が名乗り出る。即断すぎる。すげえ。
20:54 本のテーマが決まる。「2022年」
20:58 超短期アンソロ企画にしましょう、ということになる。
21:09 「小説でも絵でも漫画でもテーマに沿っていて全年齢対象なら何でもOK」くらいに決定
21:16 2名3名と増えてきたのでグループDM結成
21:24 原稿締切を12/30に決定、12/31に入稿+頒布開始することに。
22:00 要綱をちょっと修正してTwitterに放り投げる。
22:05 参加者増。「1名様ご案内でーす」「居酒屋か?」
22:15 「……居酒屋?(閃いた)」
22:21 表紙は、各自「居酒屋にいそうなキャラ」を描いた合作に決定
22:52 本のサイズをA5に決定、テンプレートを用意して共有フォルダを作り設置
23:47 表紙は「有志でちびキャラ描いておき、最後に合成」に決定

12/21

12:34 本のタイトル決定(仮題だがその後代案なかったのでそのまま使った)
23:57 最後の参加者さんご案内。自分含めなんと9名に。

12/30

23:59 締め切り

12/31

17:00 入稿、執筆者さん限定で即時通販での頒布開始(オンデマンド印刷なので)

◆完成!

執筆者9名・本文112ページのアンソロが! ほんとに企画から入稿&頒布開始まで!10日で!!できた!!
作業期間よりも!!通販ポチってから届くまでの間の方が!!長い!!!

ご参加いただいた方、年末のお忙しい時期に本当にありがとうございました…

◆主催としてやったこと

文章にしたらなんか多いけど、大した事やってない。
入稿作業とかの「誰か一人が取りまとめないとどうしようもないところ」しかやってない。

  • 人の募集
    • クソ雑な要綱作ってtwitterに垂れ流す
    • リアクションくれた人を拉致する
  • 最低限主催として決めるべきことは確定させる
    • 企画の目的:年内に1冊作る
    • 企画の方向性:書く人に楽しんでもらう、好き放題してもらう(いつも通りだが…)
    • 金銭負担とお礼:必須の金銭負担なし・献本でのお礼なし
  • 話し合いの誘導、仕切り
    • 上記以外は極力参加者さんの要望に沿いたかったので、細かい部分は話し合いつつ決定
  • テンプレートや提出先の準備
    • 共有フォルダを作り、そこにテンプレートと提出先のフォルダ作るだけ
  • 本文原稿の取りまとめ
    • 共有フォルダに置いてもらったのをチェック
    • ノンブル入れ
    • 目次とか奥付とかを作る
    • 掲載順にWordファイルに張り付けてPDF印刷したら入稿できる状態の本文原稿出来上がり
      • ちなみに掲載順=ページ確定順なので、提出され次第Wordファイルに突っ込んでた
  • 表紙の作成
    • 適当にべちゃっと背景色バケツしてタイトルを打ち込む
    • みなさんが描いてくれた素敵絵をいい感じに並べたら表紙原稿出来上がり
  • 入稿
    • 作った表紙画像と本文PDFファイルをアップロードしたら完了
  • 頒布開始
    • 入稿したのをそのままBOOTHに通すだけ。終わり。
    • 今回は「2日間だけオープンするので参加者さんは購入どうぞ、自分も買ってチェックしたのち再度オープンするのでチェック待ちたい人はまた後で」としました

◆pixivFACTORYとBOOTHを使えば簡単!

今回はこれを利用しました!!

「試しに1冊作ってみたい」「売れると思えないけどせっかくならBOOTHに置いてみたい」
あるいは「本を作るのはいいけど通販管理の手間を減らしたい」という方には一度お試しいただきたい!!!!!
(突然のステマ感)

普段の流れ

まずはいつもの方法からご紹介。

  • 原稿を作る
  • 印刷会社さんに入稿・注文する
    • 「原価×冊数+送料」で数千~数万の出費
  • 現物が届くのを待つ
  • BOOTHで公開する
  • 梱包・発送する(アンソロの場合は参加者さんに1冊ずつ献本)
    • 梱包材や送料でこまごまとした出費がある場合も
  • 在庫が余れば保管、その後も注文があり次第で随時梱包&発送作業する

印刷会社さんによっては原稿を作る前に「予約」というフローが入ることもあるっぽい?ですが、
予約が必要な会社さんを使ったことがないため予約概念がよく分からず…。

ちなみに普段は「おたクラブ」さんにお願いしがちです。
カラー印刷が超ド級に綺麗なのに少部数でも格安、その上最短3日~遅くとも10日で届く。
入稿時にプレビュー見ながらアップロードできるし面倒なノンブル入れも不要という最高な印刷会社さんです。

あとは「ペンタロー」さんも利用したことがあります。
大抵の場合はおたクラブさんの方が断然安いのですが、仕様によってはこちらの方が安いこともあります。
こちらもカラー印刷がものすごく綺麗。
入稿時のプレビューはありませんでしたがノンブルは不要ですし、対応がものすごく親切丁寧な会社さんです。
(比較的家が近いこともあり、「二種類の印刷機で試しに刷ったんですが、実物見に来られます?」というすげえお誘いをいただきました…助かりました…まさかの現物プレビュー…)

ちょっと嘘ついてる。印刷部数の参考にするために原稿作りながらBOOTHに先行で公開して予約受け付けることが多いです。

pixivFACTORYを使ったときの流れ

そこでpixivFACTORYを使うとこうなります。

  • 原稿を作る
  • 印刷会社さんに入稿・注文する
    • 「原価+送料」の出費。当然、自分では買わない場合は負担ゼロ。
  • BOOTHで公開する

はい!
以上!!
普段めちゃくちゃ面倒な「梱包・発送・在庫管理」が!一切ない!!
pixivFACTORYが全部やってくれる!!!

しかも入稿作業もおたクラブさん並みに簡単、ファイルをアップロードするだけ。
BOOTHへの登録もすごく簡単、画像や紹介文は自動で埋めてくれます。
ついでにPDF版の出力もワンボタンでできちゃいます。電子版も併せて発行したい場合は楽々。

今回のアンソロでは「参加者さんには電子版(PDF)をお配りしますが、紙で欲しい場合はBOOTHで買ってね」のスタイルでした。
「通販の手間は省きたいけど献本はしたい」という場合は、献本分だけ原価で買って通常どおり対応すればOK。
(後述のとおり単価が高いので、そこはちょっと痛いのですが…)

デメリット

個人的に思いつくのは以下4つくらいでしょうか。
状況によっては特に気になるようなことでもないのですが。

1.
pixivFACTORYが全部やってくれるということは、つまりその分、単価が高いです。
今回作ったのはA5本文モノクロ112ページで910円でした。BOOTHで頒布するとマージンを100円以上上乗せする必要があるので、最低1010円+送料。
これを例えばおたクラブさんで同等のものを最低ロットの10部刷ると1部あたりでは556円。これに梱包材などを足すことになりますが、910円に届くことはそうそうないでしょう。自分なら、BOOTH通販は700円+送料くらいで設定するかな~、という感じです。

2.
あと、個人的には原稿仕様が面倒…。
まずノンブルが必須なんです。これがおたクラブさんだと入稿のプレビュー見ながら「あっやっぱりこことここ入れ替えちゃお!」とか雑なことができるんですけど、それができない。できない方が普通と言われればそれまでですが。
そしてPDFで入稿したいときはちょっと大変。全ページを1ファイルのPDFにまとめたものを作らなきゃいけない。
漫画やイラストしかないなら画像を1枚ずつアップするだけですが、小説と混在する場合にはちょっと面倒です。
ちなみにおたクラブさんの場合は小説だけのPDFを作ってアップし、あとから挿絵の画像ファイルを間に割り込ませる、なんてことも全然可能です。

3.
注文から手元に届くまでにやや時間がかかるのも気になるかもしれません。
通常2週間程度あれば届くかも?くらいの感覚です。
例えば「入稿→自分用に注文→届いたのを自分の目で確認してOKならBOOTHで頒布開始→他の誰かが注文」という感じだと、読み手に届くまでひと月くらいかかりますね。
(確認すっとばして頒布開始しちゃえば2週間ですが)

4.
それから、紙の種類がそう多くなく、遊び紙もないですね。
シンプルな本を作る分にはあまり気にならないと思いますが、こだわりたい場合は向きません。

まとめ

ということで、単価はちょっと高いものの、
金銭的な負担と通販管理の手間を極限まで削減して個人誌でもアンソロでも作れるサービスでした!
本当に一冊作りたいだけなら対応してくれる印刷会社さんを探してお願いする手もありますが、単価はさほど変わりません。
もし他に読みたいと言ってくれる人が現れたときに応えたい思いがあるのなら!
せっかくならついでにBOOTHに置いておきませんか!
(※BOOTHに置かないことももちろん可能なので、「わが子のアルバム」みたいなガチ自分用も大丈夫)

◆…あれっ?

なんでpixivFACTORYのステマになったんだろう。
10日でアンソロ1冊作った話でした。

PHPでPDFを生成する

フリーのライブラリ「TCPDF」がメジャーな模様?

サンプルコードを動かすまでの手順

// 出力対象のHTML
$html  = "<h1>テスト出力</h1>";
$html .= "<p>本文</p>";

include "…/tcpdf/tcpdf.php";
$tcpdf = new TCPDF();
$tcpdf->AddPage();
$tcpdf->SetFont("kozgopromedium", "", 10); // 日本語フォント
$tcpdf->writeHTML($html); // htmlを指定
$tcpdf->Output('test.pdf', 'D'); // PDFを生成+ダウンロード ※ファイル名は全角文字不可の模様。工夫する必要あり

すごい簡単にダウンロードまでできてびびった。
ライセンスの問題で導入は見送ったけどそこの問題さえクリアできればな。

CSSだけで画面の下端にフッターを固定する

スクロールでついてくるやつではなく、
「ページの一番下に表示、ただしコンテンツが少なくスクロールが発生しないときは画面の一番下に表示」
というやつ。

まずHTMLがこんな感じで、固定したいfooter要素がbodyの直下にあるものとする。
他のコンテンツの構造は問わず。

<body>
  <!-- コンテンツいろいろ。構造は固定しなくてOK -->
  <footer>これを半固定にしたい</footer>
</body>


で、CSSがこう。
単純に、
bodyの中で位置指定を可能にして(position: relative)最低でも画面いっぱいの高さ(min-height: 100vh)を保証しておいてもらい、
footerはbodyの一番下(bottom: 0)に固定(position: absolute)してるだけ。

body {
    position: relative;
    min-height: 100vh;
}
footer {
    position: absolute;
    bottom: 0;
}

ファイルサイズ(バイト)をKB、MB…に変換する関数

タイトル通り。
jQuery前提、IEでも動きます。

function formatSize(byte) {
	const base = 1024;
	const unit_list = ['B', 'KB', 'MB', 'GB'];
	let res = '';
	$(unit_list).each(function(exp, unit){
		byte_unit = Math.pow(base, exp);
		if (byte < byte_unit * base) {
			res = Math.round(byte / byte_unit) + unit;
			return false;
		}
	});
	return res;
}


コール例

formatSize(1024); // "1KB"

ロジックはまあ特に難しいこともなく、
1024より小さいときはそのまま返す(なんか計算してるけどbyte_unitは1になので実質そのまま)、
1024^2より小さいときは1024^1で割る、
1024^3より小さいときは1024^2で割る…という調子。
TBにも対応するとか逆にGBはいらないとかあればunit_listに手を加えるだけでOK。
KBやMBに変換するときに小数点第何位まで出したいとかあれば要改造。

ドラッグ&ドロップでファイルをアップロードする(IE対応版)

jQuery前提です

時代に逆行してる感じがすごいですが。

以前作ったのはこちら。
ドラッグ&ドロップでファイルをアップロードする(最低限版) - アナログCPU:5108843109
ドラッグ&ドロップでファイルをアップロードする(ちょっとリッチ版) - アナログCPU:5108843109

またアップロードフォームを作る機会があったのですが、
今回はIEに対応していないとダメとのことで、↑では動かないようだったので作り直しました…。
い、今更!? IE対応すんの!?!?とは思いましたが仕方ない…。

以前作ったやつは
「フォームオブジェクトにアップロードするデータをぶちこみ、それをinput(file)要素に入れ直す。あとは普通にsubmitするだけ」
という主旨の作りだったのですが、
IEはinput要素に入れる部分がブラウザ仕様で弾かれる様子。

今回は、フォームオブジェクトをそのままJSからPOSTする方向です。
submitでないので完了時に結果表示などを伴うページ遷移をどうしても入れたい場合は厄介。

では手短に。
ドラッグ&ドロップするエリアを↓とします。(HTML)

<div class="droparea"></div>

そしてJSがこちら。

let fd = new FormData();

// ドラッグでエリアの中に入ったときの処理
$('body').on('dragover', '.droparea', function(e){ /* 見た目を変えるなどの処理 */ });
// ドラッグでエリアの外に出たときの処理
$('body').on('dragleave', '.droparea', function(e){ /* 見た目を変えるなどの処理 */ });
// エリア外でドラッグしたりドロップしたりしたときの処理(無視する)
$('body').on('dragover', function(e){ e.preventDefault(); });
$('body').on('drop', function(e){ e.preventDefault(); });

// エリア内でドロップしたときの処理(フォームオブジェクトに突っ込む)
$('body').on('drop', '.droparea', function(e){
	e.preventDefault();
	let files = e.originalEvent.dataTransfer.files;
	for ( let i = 0, len = files.length; i < len; i++ ) {
		fd.append('userfile[]', files[i]);
	}

	// 送信 ※ドラッグ&ドロップ直後にアップロードしない場合は適宜外に出して調整
	send();
});

// 送信処理
function send(){
	let xhr = new XMLHttpRequest();
	xhr.open('POST', encodeURI('/upload.php')); // ★POST先:適宜変更する
	xhr.onreadystatechange = function(){
		if ( xhr.readyState == 4 ) {
			if ( xhr.status == 200 ) {
				// 成功時の処理
				console.log(xhr.responseText); //例えばこれだとPOST先の返却値をコンソールに表示
			} else {
				// 失敗時の処理
			}
		}
	};
	xhr.send(fd);
}

アップロード先(↑の例だとupload.php)は今回とあんまり関係ないので最低限の動作確認分だけ。

<?php
var_dump($_FILES);

ちなみにファイル以外のものをPOSTしたいときもファイルと同じように追加できます。
「fd.append('キー名', 値);」「fd.set('キー名', 値);」のいずれかで追加が可能で、文字通りappendは「追加」、setは「もし同じものがあれば上書き」です。
…が、IEはsetが使えず、今回の趣旨で言うと、appendだけでなんとかする必要があります。ええ……
FormData.append() - Web API | MDN
FormData.set() - Web APIs | MDN

PHP側では通常通り$_POSTで受け取れます。

GoogleのMaterial Iconsをダウンロードして使う

Font Awesomeをダウンロードして使う話はこちら。


Googleの提供するCDNのフリーアイコン、Material Iconsをダウンロードして使ってみる。
外部接続したくない案件なのだ。
個人的にはFont Awesomeのアイコンの方が好き。

1. 何はともあれダウンロード

GitHubからzipをダウンロード。
https://github.com/google/material-design-icons/releases

これを書いている2021/07/06現在、バージョンは4.0.0。

308MBという重さにびびる。
とはいえ、実際にサーバーに置くのはそこまでではない(使い方による)。
ちなみにFontAwesomeの方はzipが5MB、実際にサーバーに置くのが2.8MB。

2. zipを展開する

ダウンロードしたzipを展開します。
「右クリックして展開!」とかやっちゃうと重すぎて固まるかもしれません。
上手くいかない場合は解凍用のソフトなどを試しましょう。

3. WEBアプリに設置する

必要なのはどれだ??と迷いつつ試してみたところ、
fontディレクトリ内の各フォントデータ(*.ttfや*.otf)だけでOKでした。
それも、自分が使いたいものだけ選んで置けば大丈夫。

ただ、そのフォントデータを読み込むためのCSSなどを別途自分で書く必要があります。

4. タグを埋め込んで動作確認

公式ドキュメントを参考に、下記のようにしてみました。

公式ドキュメントはこちら。
https://developers.google.com/fonts/docs/material_icons


CSS

@font-face {
  font-family: 'Material Icons';
  font-style: normal;
  font-weight: 400;
  src: local('Material Icons'),
    url(/css/fonts/MaterialIconsRound-Regular.otf);
}
.material-icons {
  font-family: 'Material Icons';
  font-weight: normal;
  font-style: normal;
  font-size: 24px;  /* Preferred icon size */
  display: inline-block;
  line-height: 1;
  text-transform: none;
  letter-spacing: normal;
  word-wrap: normal;
  white-space: nowrap;
  direction: ltr;
  /* Support for all WebKit browsers. */
  -webkit-font-smoothing: antialiased;
  /* Support for Safari and Chrome. */
  text-rendering: optimizeLegibility;
  /* Support for Firefox. */
  -moz-osx-font-smoothing: grayscale;
  /* Support for IE. */
  font-feature-settings: 'liga';
}

アイコン表示例

<span class="material-icons">face</span>

これで表示されればOK。
ただ、fontawesomeと比べるとなんとなく汚いので(配置とか余白の微妙なニュアンス)、ちょっと自力で調整が必要かな…という感じ。

自分用メモ

  • きれいな書き方あればまとめる