お知らせ

現在サイトのリニューアル作業中のため、表示が崩れているページが存在することがあります。
2024/01/22 02:22 言語::PHP技術::CGI

ふとした気づき

今時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'];
2024/01/22 02:18 言語::HTML言語::CSS

画像マーカーを使ったリストタグを使った時に文字列がvertical-align: middle的になってほしい!

が結論から言うと多分無理です

なってくれないんだなこれが!

  • 残念ながら現実にはなりません

縦中央に来ない

  • 上の画像のソースはこんなん
    • ::beforecontent に画像を置くとかしても無駄です
<ul>
  <li>リストの要素だよ~</li>
  <li>改行のある<br>リストの要素だよ~</li>
</ul>
ul {
    list-style-image: url("https://i.imgur.com/hX2OCbY.png");
}

li {
    vertical-align: middle;
}

どうにか対策してみる

  • 一見するとなんとかなったように見えますが、改行すると崩れます
    • ぶっちゃけ無理にリストタグ使う必要もないと思うので、素直に 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;
    }
2024/01/22 02:13 ソフトウェア::Git

SSHが使えない悲劇に出会った時に。CentOS 7.7で確認。

パスワードは平文保存されるっぽいので、そこら辺は注意が必要。

  1. 認証情報をキャッシュする設定にする
    1. git config --global credential.helper cache
  2. キャッシュのタイムアウトを1年くらいにしとく
    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>
  );
};
2024/01/22 01:50 Node.js::npm

自作npmコマンドを蹴る方法のメモ

Env Ver
Node.js 12.18.3
npm 6.14.8

手順

  1. Node.jsのプロジェクトを作成
    1. npm initとか適当に
  2. package.jsonに以下を追加
"bin": {
  "my-npm-command": "./index.js"
}
  1. Node.jsのCLIを作成
    1. 以下はサンプル
#!/usr/bin/env node
console.log('my-npm-command');
  1. npm linkを叩き、my-npm-commandを実行して動いてればOK
    1. 外したくなったらnpm unlink