ふとした気づき
今時CGIなんて言わない?知らない?そんなこたぁいいんですよ。
ふと思ったんですよ、CGIとCLIアプリって本質的に同じものなんじゃないかなって。
だってPHPってこんなふうに書いてブラウザでアクセスしたらいろはにほへと
って出るじゃないですか?
そしてこれをphp index.php
みたいにして叩いてもいろはにほへと
って出ますよね?
<?php
echo 'いろはにほへと';
そう、気付いてしまったのです。
実はCGIって本質的にはCLIアプリなのではないかと…。
むしろ何が違うんでしょう?
仕組みを調べてみることに
気になったのでどういう仕組で動いてるのか軽く調べるために、敢えてC言語でCGIを作ってみることに。
今までC言語でCGIとか狂人のやることって印象があったのですが、意外とやってみると大したことはないというか、まぁ大したものを作ってないから当たり前なんですが…。
これが何をしているかというと、環境変数を取ってきて標準出力に吐いてるだけなので、どっからどう見てもCLIアプリです。
#include <stdio.h>
// getenv
#include <stdlib.h>
// strcmp
#include <string.h>
/*
get path for after hostname
*/
char* getPath(void) {
char *path = getenv("REQUEST_URI");
return path;
}
int main(void) {
// put http header
printf("Content-type: text/plain\n\n");
char *path = getPath();
// show current path
printf("Current path: %s\n", path);
// routing, required .htaccess to serve on apache
if (strcmp(path, "/foo") == 0) {
printf("hoge");
} else if (strcmp(path, "/bar") == 0) {
printf("piyo");
} else {
printf("fuga");
}
return 0;
}
実際に動かしてみたところ
CGIとして
CLI として
辿り着いた結論
恐らくこれは動作環境が重要なのであって、多分CGIとCLIアプリの作りとしては大きな違いはないのではないか?というのが辿り着いた結論です。
いやまぁ引数をargv
から取るか環境変数から取るかは結構違う気もしますが、基本的に表示したいものを標準出力に吐く点は同じですし、別にCGIでTCPソケットを触るわけでもないので、同じようなものでは?と思った次第。
これは多分、 HTTPサーバーを通すことで標準出力がHTTPレスポンスに出力され、 Xサーバーを通すなら画面に、プリンタサーバーを通せば紙にといった具合に、どこのサーバーを通して標準出力をするかで出てくるところが変わるのでは?と感じました。(細かいことを言うともっと複雑らしい)
多分ApacheとかのHTTPサーバーはTCPソケットをいい感じにやってくれて、 HTTPヘッダを環境変数に入れてCGIスクリプトを起動といったところをしてくれているのではないかと思ったので、暇な時にTCP通信から始めるHTTPサーバーの実装でもやってみたいところですね…。
おまけ
取り敢えずPHPのCGIをCLIとして動かせるやつです。
<?php
echo $_SERVER['REQUEST_URI'];
画像マーカーを使ったリストタグを使った時に文字列がvertical-align: middle
的になってほしい!
が結論から言うと多分無理です
なってくれないんだなこれが!
- 残念ながら現実にはなりません
- 上の画像のソースはこんなん
::before
のcontent
に画像を置くとかしても無駄です
<ul>
<li>リストの要素だよ~</li>
<li>改行のある<br>リストの要素だよ~</li>
</ul>
ul {
list-style-image: url("https://i.imgur.com/hX2OCbY.png");
}
li {
vertical-align: middle;
}
どうにか対策してみる
- 一見するとなんとかなったように見えますが、改行すると崩れます
- ぶっちゃけ無理にリストタグ使う必要もないと思うので、素直に div とかで代替するのが一番だと思います
- 何が何でもリストタグ使いたい場合はリストタグでラップしてしまうのが一番でしょうね…
- ぶっちゃけ無理にリストタグ使う必要もないと思うので、素直に div とかで代替するのが一番だと思います
- 上の画像のソースはこんなん
- リストのマーカーを使うことを放棄しているので、画像を抜けると字が落ちるのはどうしようもないですね
<ul>
<li>リストの要素だよ~</li>
<li>改行のある<br>リストの要素だよ~</li>
</ul>
.ul {
list-style: none;
}
.li::before {
padding-right: 3px;
min-height: 36px;
content: url("https://i.imgur.com/hX2OCbY.png");
vertical-align: middle;
}
SSHが使えない悲劇に出会った時に。CentOS 7.7で確認。
パスワードは平文保存されるっぽいので、そこら辺は注意が必要。
- 認証情報をキャッシュする設定にする
git config --global credential.helper cache
- キャッシュのタイムアウトを1年くらいにしとく
git config --global credential.helper 'cache --timeout=31536000'
react-routerでRouteを切る実装例
確認環境
Env | Ver |
---|---|
React | 17.0.1 |
react-router-dom | 5.2.0 |
TypeScript | 4.1.3 |
サンプルコード
index.tsx
- ここに大元のルーティングを実装
import React from 'react';
import ReactDOM from 'react-dom';
import './index.scss';
import { BrowserRouter } from 'react-router-dom';
import { RootRoute } from './routes/RootRoute';
// ドメインルート以外にReactを設置する場合に必要
// e.g. `https://www.example.com/react/` に設置する場合 `/react` を設定
const basename = process.env.REACT_APP_BASE_NAME ?? undefined;
ReactDOM.render(
<React.StrictMode>
{/* `useHistory()` 用のDIラッパー */}
<BrowserRouter basename={basename}>
{/* ルーティング設定をまとめたコンポーネント */}
<RootRoute />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
AppRoute.ts
- ルーティングの定義、これがあると後々の管理が楽
- スプレッド演算子で
Route
に対して展開できるように記述しておく
export const AppRoute = {
// React のルート定義
root: {
path: '/',
key: '/',
exact: true, // 完全一致
component: App,
},
// 404 定義
notfound: {
component: NotFound,
},
// `/foo` 以下のルーティング定義
foo: {
// `/foo` のルート定義
root: {
path: '/foo',
key: '/foo',
component: FooRoute,
},
// 以下、 `/foo` 配下のページのルーティング定義
hoge: {
path: '/foo/hoge',
key: '/foo/hoge',
component: HogePage,
},
piyo: {
path: '/foo/piyo',
key: '/foo/piyo',
component: PiyoPage,
},
},
};
RootRoute.tsx
- 各階層の基底ルーティング管理
export const RootRoute = () => {
return (
{/* `Route` は `Switch` で囲む */}
<Switch>
{/* root */}
<Route {...AppRoute.root} />
{/* foo */}
<Route {...AppRoute.foo.root} />
{/* bar */}
<Route {...AppRoute.bar.root} />
{/* 404 */}
<Route {...AppRoute.notfound} />
</Switch>
);
};
FooRoute.tsx
/foo
階層配下の管理用
export const FooRoute = () => {
return (
{/*
`Context` は `Switch` の外に出す
`Switch` の中に `Context` を書くと更に `Switch` でネストする必要がある
*/}
<FooContext.Provider value={FooContextDefault}>
<Switch>
{/* eslint-disable-next-line array-callback-return */}
{Object.entries(AppRoute.foo).map(([idx, route]) => {
if (idx !== 'root') {
/* `'root'` 以外の全ノードを展開 */
return <Route {...route} />;
}
})}
{/* 404 */}
<Route {...AppRoute.notfound} />
</Switch>
</FooContext.Provider>
);
};
自作npmコマンドを蹴る方法のメモ
Env | Ver |
---|---|
Node.js | 12.18.3 |
npm | 6.14.8 |
手順
- Node.jsのプロジェクトを作成
npm init
とか適当に
- package.jsonに以下を追加
"bin": {
"my-npm-command": "./index.js"
}
- Node.jsのCLIを作成
- 以下はサンプル
#!/usr/bin/env node
console.log('my-npm-command');
npm link
を叩き、my-npm-command
を実行して動いてればOK- 外したくなったら
npm unlink
- 外したくなったら