CodeIgniterでCSS効かせて静的ページを作るまで【地味にハマった】

# はじめに
全然業務でコードに触れないので、広範囲に自分のスキルを上げるためにPHPでWebアプリを作っています。
実践重視。
FWにはCodeIgniter3を採用してみました。

今回はせっかくなので触ったことないFWでやってみたい欲が出たので、初めて触れるCodeIgniter3にしました。

少ない設定とルールで、素のPHPのノリでサクサク書ける、という感じで聞いていたので、サクサク行けるでしょう！と思っていたら。。。
チュートリアルは難なく出来たものの、そこから自分の好きなように進めようと思ったら、設定周りで意外とハマった(勝手にハマっていたのもある)ので、未来の自分が二の轍踏まないように記録。

というか公式に細かいこと書いてないのがつらい。。。(責任転嫁)

# 前提条件

* Apache
    * nginxはURLリライティングの設定周りが違うはず。。。
* RedHat系のLinuxディストリビューション(CentOSやAmazonlinuxなど)
    * Debian系(Ubuntuなど)だとパスが違うかもです。適宜読み替えてください。

# URLからindex.phpを省くようにする

CodeIgniter3は、特に設定しないでいるとURLが次のようになります。

```
http://example.com/index.php/[controller]/[method]/
```

…index.phpがジャマですね。
この`index.php`を消し去るためには、**割といろいろ変更する必要があります。**
ひい早速面倒くさい。

まずは、Apacheの`httpd.conf`と`.htaccess`の両方を設定する必要があります。

## httpd.conf

`.htaccess`を有効にするためには、ドキュメントルート以下での`AllowOverride`を許可する必要があります。
Apacheの設定ファイルは`/etc/httpd/conf/httpd.conf`。

編集するべき箇所は、以下の辺り。

```
#
# This should be changed to whatever you set DocumentRoot to.
#
<Directory "/var/www/html">

#
# Possible values for the Options directive are "None", "All",
# or any combination of:
#   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
#
# Note that "MultiViews" must be named *explicitly* --- "Options All"
# doesn't give it to you.
#
# The Options directive is both complicated and important.  Please see
# http://httpd.apache.org/docs/2.2/mod/core.html#options
# for more information.
#
    Options Indexes FollowSymLinks

#
# AllowOverride controls what directives may be placed in .htaccess files.
# It can be "All", "None", or any combination of the keywords:
#   Options FileInfo AuthConfig Limit
#
    AllowOverride None # <<<===ここ！！！！！
```

デフォルトでは`None`が設定されているので、`All`にしてあげます。

```
AllowOverride All
```

### ポイント
`<Directory "/var/www/html">`の下である、というのがポイントです。
※ドキュメントルートを変えた場合は、そこをディレクトリとして指定します。

`AllowOverride`自体は何箇所もあります。
`AllowOverride`は **.htaccessを有効にするかどうか、に等しい** ので、よく分からず全部変えると割と怖いことになります。

## httpd.confその2

`httpd.conf`の変更箇所はもう一箇所あります。

```
#
# DirectoryIndex: sets the file that Apache will serve if a directory
# is requested.
#
# The index.html.var file (a type-map) is used to deliver content-
# negotiated documents.  The MultiViews Option can be used for the 
# same purpose, but it is much slower.
#
DirectoryIndex index.html index.html.var # <<<===ここ!!!!!
```

`DirectoryIndex`に`index.php`を追加してあげます。
ここでは、トップページとして使えるファイル名を指定しています。
当然`index.php`が起点になるわけなので、これを追加する必要があります。

```
DirectoryIndex index.php index.html index.html.var
```

### Apache再起動

変更を反映する時は、必ずApacheを再起動します。
**RedHat系の場合は、6系か7系かで違うので要注意。**
私は7系に慣れてしまったので、Amazonlinuxなどの6系に未だに慣れないのです。。。

6系: `service httpd restart`
7系: `systemctl restart httpd.service`

## .htaccess

みんな大好き`.htaccess`。
リダイレクトやアクセス制御でお世話になっております。**出来れば触りたくない。**

この設定については、公式のやり方そのままで良いと思います。
[http://codeigniter.jp/user_guide/3/general/urls.html](http://codeigniter.jp/user_guide/3/general/urls.html)

```
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
```

ネットで調べると下記のような別解もあるようですが、実害出るまでは公式のやり方で大丈夫でしょう(多分)
cf. [http://taitan916.info/blog/?p=2515](http://taitan916.info/blog/?p=2515)

```
RewriteEngine on
RewriteCond $1 !^(index\.php|images|.+\.css$|.+\.js$|.+\.png$|.+\.jpg$|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L]
```

**先述の`AllowOverride`の設定が出来ていないと、いくらやってもリダイレクトが効かないので要注意。**

私はここで1時間くらい詰まりました。結果はただの凡ミスでしたが。。。
> ※Dockerで環境構築していたのですが、`AllowOverride All`にした`httpd.conf`を適切なところにCOPY出来ていなかったがために、`AllowOverride All`になっていなかった、と。そして、それにずっと気づけなかった、というオチです。


これで終わってくれれば良かったんですが。。。まだ設定します。

## application/config/config.php

CodeIgniterのconfigファイルをいじります。

### index_page

ここの箇所を、

```
$config['index_page'] = 'index.php';
```

こうします。

```
$config['index_page'] = '';
```

何でかと言われても、ソースコメントにこう書いてある以上、そうするしか無いんでしょう。

```
If you are using mod_rewrite to remove the page set this variable so that it is blank.
```

## 結果どうなるか

これでアクセス出来るようになります。

```
http://example.com/[controller]/[method]/
```

これでURLが様になりましたね。一安心。

# CSSをviewに読み込む

割と頭抱えたのがここでした。
**CSSファイルどうやって読み込むんや！**
普通に`link`で読み込むにしても、パスどうやって取得するの。。？など全く分からず。

チュートリアルではCSS使ってないですし、割と真面目にどうやって使うんだよ、とまた小一時間悩みました。
CakePHPでは、最初のデモページでCSSファイル読み込んでるので、その書き方見ればすぐ分かるんですが。。。
CodeIgniterはよりによってデモページが **CSS直書き** なんですよね。参考にならぬ。。。

ここが参考になりました。
[https://ameblo.jp/nikatabushi/entry-11718971984.html](https://ameblo.jp/nikatabushi/entry-11718971984.html)

## /application/config/config.php

### base_url

**一番ハマってたところ。**

こう書いてあるのを、

```
$config['base_url'] = '';
```

こうします。

```
$config['base_url'] = 'http://localhost/';
```

**ここが指定されていないと、後述するURLヘルパーがURLをちゃんと取得出来ず、CSSが404になる原因となります。**
ここのせいでずっと頭抱えてました。おのれ。

今はローカルで動かしているので、localhostにしていますが、本番の時には書き換えるか、ホスト名見て条件分岐するなどが必要かと思います。

## uri_protocol

執筆時点での最新版(3.2.0)なら大丈夫ですが、書き換えてる例をちらほら見たので、一応。
こうなってれば大丈夫です。

```
$config['uri_protocol']	= 'REQUEST_URI';
```

# /application/config/autoload.php

CodeIgniterは、モデルにせよ何にせよ、基本的には使いたいモジュールは **明示的な呼び出しが必要** です。
(モデルとか命名規則で勝手に紐づくFWが多い中、少し変わってる気がします。。。)

ですが、どこのコントローラーでも絶対使う、と分かってるものを毎回コンストラクタで呼び出すのも効率悪いので、オートローダーに登録します。
今回はURLヘルパーを登録しておきます。

```
$autoload['helper'] = array('url');
```

# CSSをどこに置くか

結論は、 **`application`や`system`が並んでいる階層** です。
本当は`application`の下に置きたかったですが、うまく行きませんでした。
※この辺り詳しい方は教えてください！

`application`や`system`が並んでいる階層に`assets`というフォルダを作り、その中に作りました。

```
$ tree -l -L 1
.
├── DCO.txt
├── application
├── assets
├── build-release.sh
├── composer.json
├── contributing.md
├── index.php
├── license.txt
├── readme.rst
├── src.iml
├── system
├── tests
└── user_guide_src

$ tree assets -l -L 1
assets
├── css
├── fonts
└── js
```

もう既に置いてあるのもありますが。どうせ`fonts`とか`img`とかいろいろ増えるでしょうから、`assets`という形でまとめておくのが良いでしょう。

# ビューでどう書くか

```html
<html lang="ja">
	<head>
		<title>テストページ</title>
		<meta charset="UTF-8">
		<link rel="stylesheet" href="<?php echo base_url()?>assets/css/bootstrap.min.css">
	</head>
	<body>
		<h1>ぱんつぁーふぉー！</h1>
	</body>
</html>
```

`href`だけ取り出すとこんな感じです。

```
href="<?php echo base_url()?>assets/css/bootstrap.min.css"
```

HTML雑っ。

`base_url()`がよしなにURLを取得して、適切に割り当ててくれます。
**ここでよしなにやってくれるためには、先述の`application/config/config.php`の`base_url`の設定が必須になります。**
ここに気づくまでだいぶ時間かかりました。
分かれば何てことはないんですけどね。

分かりやすくするために`<?php echo`と書きましたが、もちろんショートタグで`<?=`としても可。
自分が普通に書くならショートタグ一択。

# おわりに

CodeIgniterまだ少し触っただけではありますが、慣れてしまえば割とサクサク行けそうな感じのするFWだと思いました。
それだけに、設定周りが意外にとっつきにくい印象です。
**この辺りの情報、全然公式に載ってないんですもの！**
もう少しドキュメントがしっかりすると良いような気がします。

さあこれで後は作るだけ！