CORESERVER で Python の CGI を動かす

## 概要
- GMOデジロックのレンタルサーバー「コアサーバー」で Python の CGI を動作させる

## 今回の環境
- 料金プラン: ビジネスプラン「CORE-B」 (30日間無料お試しトライアル期間中)
- サーバー: b1.coreserver.jp
- Python 3.6.8

## 設定: CGI 実行ファイルの拡張子を cgi または py にする

.cgi ファイルは最初から CGI として実行できるようになっているので、実行権限をつけて置いておけば良い。

```
$ ls -l ~/public_html/hello.cgi
-r-xr-xr-x 1 alice hpusers 414 12月 12 20:08 /virtual/alice/public_html/hello.cgi
```

拡張子を py にしたい場合、 .py ファイルは CGI として実行できるようになっていないので、 CGI として実行されるための設定を記述した .htaccess ファイルを設置する。

```
$ ls -l ~/public_html/.htaccess 
-rw-r--r-- 1 alice hpusers 27 12月 12 18:09 /virtual/alice/public_html/.htaccess
```

.htaccess の中身は以下のように記述する。

```.htaccess
AddHandler cgi-script .py
```

## Hello World 表示サンプル (hello.cgi)

### ソースコードの場所

```
$ ls -l ~/public_html/hello.cgi
-r-xr-xr-x 1 alice hpusers 414 12月 12 20:08 /virtual/alice/public_html/hello.cgi
```

### ソースコード

```python
#!/usr/local/bin/python3

import io
import sys

# 出力ストリームの文字エンコーディングを指定
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

# HTTP ヘッダ
print('Content-Type: text/html; charset=utf-8')
print() # blank line, end of headers

# HTML 本文
print('<html><body>')
print('Hello, world.<br>')
print('こんにちは、世界。<br>')
print('</body></html>')
```

### アクセス結果

```
$ curl http://alice.b1.coreserver.jp/hello.cgi
<html><body>
Hello, world.<br>
こんにちは、世界。<br>
</body></html>
```

## 入力値の表示サンプル (message.py)

### ソースコードの場所

```
$ ls -l ~/public_html/message.py 
-r-xr-xr-x 1 alice hpusers 565 12月 12 20:14 /virtual/alice/public_html/message.py
```

### ソースコード

```message.py
#!/usr/local/bin/python3

import cgi
import html
import io
import sys

# 出力ストリームの文字エンコーディングを指定
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

# message パラメータの値を取得
form = cgi.FieldStorage()
message = form.getfirst('message', 'Hello, world.')

# HTTP ヘッダ
print('Content-Type: text/html; charset=utf-8')
print() # blank line, end of headers

# HTML 本文
print('<html><body>')
print(f'message: {html.escape(message)}') # HTMLエスケープして出力
print('</body></html>')
```

### アクセス結果

```
$ curl http://alice.b1.coreserver.jp/message.py?message=%E7%BD%AA%E3%81%A8%C3%97
<html><body>
message: 罪と×
</body></html>
```

## 外部ライブラリ利用サンプル (draw.py)

### パッケージをインストール

今回は ~/my-space ディレクトリに NumPy パッケージと Matplotlib パッケージをインストールする。

```
$ python3 -m pip install numpy matplotlib --target ~/my-space
```

~/my-space ディレクトリにパッケージが設置される。

```
$ ls ~/my-space
__pycache__                                 numpy
bin                                         numpy-1.17.4.dist-info
cycler-0.10.0.dist-info                     pkg_resources
cycler.py                                   pylab.py
dateutil                                    pyparsing-2.4.5.dist-info
easy_install.py                             pyparsing.py
kiwisolver-1.1.0.dist-info                  python_dateutil-2.8.1.dist-info
kiwisolver.cpython-36m-x86_64-linux-gnu.so  setuptools
matplotlib                                  setuptools-42.0.2.dist-info
matplotlib-3.1.2-py3.6-nspkg.pth            six-1.13.0.dist-info
matplotlib-3.1.2.dist-info                  six.py
mpl_toolkits
```

### ソースコードの場所

```
$ ls -l ~/public_html/draw.py 
-r-xr-xr-x 1 alice hpusers 922 12月 15 01:53 /virtual/alice/public_html/draw.py
```

### ソースコード

```draw.py
#!/usr/local/bin/python3

import io
import sys

# モジュール検索パスにライブラリのパスを追加
sys.path.append('../my-space')

# NumPy と Matplotlib を読み込む
import numpy as np
import matplotlib
import matplotlib.pyplot as plt

# データの作成
x = np.arange(0, 6, 0.1) # 0から6まで0.1刻みで生成
y1 = np.sin(x)
y2 = np.cos(x)

# グラフの描画
plt.figure(figsize=(4, 3), dpi=160) # 画像サイズ
plt.plot(x, y1, label='sin')
plt.plot(x, y2, linestyle = '--', label='cos') # 破線で描画
plt.xlabel('x') # x軸のラベル
plt.ylabel('y') # y軸のラベル
plt.title('sin & cos') # タイトル
plt.legend() # 凡例

# PNG 画像バイト列を生成
image = io.BytesIO()
plt.savefig(image, format='png')
image.seek(0)

# HTTP ヘッダ
sys.stdout.buffer.write(b'Content-Type: image/png\n\n')

# 画像バイナリデータを出力
sys.stdout.buffer.write(image.read())
```

### アクセス結果

```
$ curl --dump-header - -s http://alice.b1.coreserver.jp/draw.py --output a.png
HTTP/1.1 200 OK
Date: Sat, 14 Dec 2019 17:05:05 GMT
Server: Apache
Vary: User-Agent
Transfer-Encoding: chunked
Content-Type: image/png
```

保存した a.png ファイル。

![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/a53e1145-151a-d0f9-eeaa-77b73f4db8c5.png)

## 参考資料

- [各種パス（PATH）について \| 基本的な質問 \| よくある質問 \| レンタルサーバー CORESERVER（コアサーバー） \- 30日間無料お試しし](https://www.coreserver.jp/support/faq/server-path.php)
- [21\.2\. cgi \-\-\- CGI \(ゲートウェイインタフェース規格\) のサポート — Python 3\.6\.10rc1 ドキュメント](https://docs.python.org/ja/3.6/library/cgi.html)
- [pip install — pip 19\.3\.1 documentation](https://pip.pypa.io/en/stable/reference/pip_install/)
- [6\. モジュール \(module\) — Python 3\.6\.10rc1 ドキュメント](https://docs.python.org/ja/3.6/tutorial/modules.html)
- [【python】任意のライブラリをインポートするためパスを通そう！ \| 侍エンジニア塾ブログ（Samurai Blog） \- プログラミング入門者向けサイト](https://www.sejuku.net/blog/66459)
- [Python vs Ruby 『ゼロから作るDeep Learning』 1章 sin関数とcos関数のグラフ \- Qiita](https://qiita.com/niwasawa/items/6d9aba43f3cdba5ca725)
- [Pythonでmatplotlibとio\.BytesIOの使用例の作成｜コンピュータ｜ブログ｜Take3's web](https://www.valuestar.work/news/archives/78)