「Develop」の版間の差分

提供:senooken JP Wiki
(PhpStorm Encoding)
(Other Window)
 
(同じ利用者による、間の56版が非表示)
199行目: 199行目:


一時的に回避したい場合、[の直前に何か文字があれば解釈されない。スペース開けて[があるとオートコンプリート扱いになる。
一時的に回避したい場合、[の直前に何か文字があれば解釈されない。スペース開けて[があるとオートコンプリート扱いになる。
===== 書式なしペースト =====
[https://qiita.com/kentoak/items/fbba0b9e3e735893a35e Confluenceで書式なしペースト(Ctrl+Shift+V)を有効にする #Confluence - Qiita]
[?]-[キーボードショートカット]-[General]-[▫️Enable General Shortcuts] にしてオフにすると有効になる。
[表の上部にペースト] と競合していたらしい。
==== マクロ ====
[https://ja.confluence.atlassian.com/doc/macros-139387.html マクロ | Confluence Data Center 9.2 | アトラシアン製品ドキュメント]
いくつか有用なマクロがある。
* [https://ja.confluence.atlassian.com/doc/children-display-macro-139501.html 子ページ表示マクロ | Confluence Data Center 9.2 | アトラシアン製品ドキュメント]
* [https://www.ricksoft.jp/blog/articles/001510.html Confluence(コンフルエンス)の一部内容を折りたたみで非表示できる「展開」マクロを使ってみよう - リックソフトブログ]
==== Other ====
===== パーマリンク =====
[https://confluence.atlassian.com/confkb/the-differences-between-various-url-formats-for-a-confluence-page-278692715.html The Differences Between Various URL Formats for a Confluence Page | Confluence | Atlassian Documentation]
Confluenceのページ新規作成時、パーマリンクが自動生成される。規則がある。
以下の条件にマッチしたら、padeId URLになる。それ以外は、タイトル名のURLになる。
* [% & ? / ¥ ; " + :] などのようなURLの予約文字。
* 非ラテン文字。
* ページタイトル末尾が英数字以外の場合。
===== ページ履歴 =====
ページ右上のメニュー-[ページ履歴]から履歴を確認できる。差分も確認できる。
===== ページ移動 =====
[https://ja.confluence.atlassian.com/doc/move-and-reorder-pages-146407727.html ページの移動と順序の変更 | Confluence Data Center 9.2 | アトラシアン製品ドキュメント]
ページ右上のメニュー-[移動]


== Tool ==
== Tool ==
258行目: 292行目:
```
```


== Coding ==
==== GNU screen ====
[https://qiita.com/SAITO_Keita/items/b79ebc5af64aad28fc4a#:~:text=%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AB%E6%8E%A5%E7%B6%9A%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E7%8A%B6%E6%85%8B%E3%81%A7%E3%82%AD%E3%83%BC,%E6%A8%AA%E3%81%AB%E5%88%86%E5%89%B2%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82 GNU Screenコマンドをつかってみる #screen - Qiita]


=== タイムゾーン ===
screenコマンド実行後に、C-a押下後に対応するキーを押して各種操作を実行する。
[https://qiita.com/dmikurube/items/15899ec9de643e91497c タイムゾーン呪いの書 #timezone - Qiita]


3文字形式は避けたほうが無難。
キー操作以外に、コマンドも用意されている。C-a :でコマンドラインモードに入る。


タイムゾーン名で判定する実装があるので、UTC-9なども避けたほうがいい。
特に重要な操作。


tz databaseのAsia/Tokyoなどの確実性が高い。
* Help
=== Regular Expression ===
** C-a ?
正規表現。重要。覚えにくいが重要なものをメモしておく。
** Command:help
* Window
** C-a c/C-a C/Command:screen=Windowを生成。
** C-a space/C-a n/C-a C-n/Command:next=次のWindowへ移動。
** C-a p/C-a C-p/C-a C-h/C-a Backspace/Command:prev=前のWindowへ移動。
* 画面分割: Regionを分割してそこにWindowを割り当てる。
** C-a S=横分割
** C-a |=縦分割
** C-a TAB/Command:focus=分割画面の移動。
* クローズ
** C-a X/Command:remove=現在のRegionを終了。
** C-a Q/Command:Only=現在以外のRegionを終了。


後ろからマッチ。cが置換対象。
===== .screenrc =====


==== Case ====
====== スタートアップメッセージ ======
/[^c]*$/: cより右端
startup_message off


===== マッチの前後の挿入 =====
====== スクロール ======
https:/vim.fandom.com/wiki/Power_of_g
[https://www.robotech-note.com/entry/2017/01/27/082929 linux screen中にマウスホイールでスクロールする方法 - 技術メモ集]
:g/GST_.*("/s/^/LOG(INFO) << "DEBUG";/r/
行頭・行末で引っ掛ける。


===== 関数にログ =====
デフォルトだとマウススクロールなどに対応していない。以下の設定で対応でき、通常使用で問題なくなる。
  :%s/([^")]*)/) /([a-z]* /)*{/&/rLOG(INFO) << "/1";/r/g
  termcapinfo xterm* ti@:te@
考慮するケース
  defscrollback 100000
  double currentTime() const override { return m_element->currentTime(); }


=== glob ===
=== Binary ===


* [https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/functions/glob.html glob]
==== .so ====
* [https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/utilities/V3_chap02.html#tag_18_13 Shell Command Language]
ソフトウェアの依存関係などの調査で.soファイルの分析を行うことがある。


重要。正規表現とは似ているが異なる、パターンマッチング記法 (Pattern Matching Notation)。主に、globで採用されており、ディレクトリー・ファイルのマッチングで使われる。
[https://zenn.dev/nyoho/scraps/3651de0bd0b313 .soファイルの中のシンボル探し]


使用可能な記号は以下3個。以下の3文字は\でエスケープできる。
* nm
* ldd
* string


* ?: 任意の1文字にマッチ。
=== Diff ===
* *: 任意の0以上の文字にマッチ。
差分確認ツール。コードレビューなどで重要。
* [: []内の1文字にマッチ。正規表現の各括弧と同じ。ただし、先頭の否定が^ではなく、!。


ファイル名マッチ時には、追加で特殊なルールがある。
==== About ====
Macが鬼門。


.から始まるファイル名へのマッチには、.が必要。つまり、*?は先頭の.にはマッチしない。[!a] のような否定形の各括弧記法も.にはマッチしない。加えて、先頭の[.]もマッチするかは不定(unspecified)。
M1 Macで使用可能なものの選択肢が極端に狭い。


globで.ファイルを含めたい場合、工夫が必要 ([https://www.php.net/manual/ja/function.glob.php PHP: glob - Manual])。
https://chatgpt.com/c/678e249e-84f0-800b-b8da-7385d9aaf819
.[!.]* *
{| class="wikitable"
上記のように.ファイルのマッチとそれ以外を指定する必要がある。
|+
 
!name
<code>.[!.]*</code> は、<code>.</code>と<code>..</code>以外の.<code>.</code>始まりのファイルにマッチする。
!OS
 
!Free
<code>.*</code>を指定すると、<code>.</code>/<code>..</code>がマッチするので注意する。最近のシェルは、シェル側で気を利かせているようで、<code>.*</code>だと<code>.</code> /<code>..</code>はマッチしない。
!GUI
 
!directory
=== 引用符のネスト ===
!image
シェルやプログラミング言語で、文字列リテラルの表現などで、一重引用符'と二重引用符"を使う。
!comment
 
|-
JSON作成や変数展開などで、これらをネストさせたいことがある。その基本的な考え方を整理する。
|FileMerge
|Mac
|x
|x
|x
|
|Xcode付属ツール。悪くない。が、Mac専用。
|-
|P4Merge
|x
|x
|x
| -
|x
|ディレクトリー比較ができないのが惜しい。
|-
|DiffMerge
|x
|x
|x
|x
| -
|悪くない。が開発停止。MacはIntel版のみ。
|-
|WinMerge
|Windows
|x
|x
|x
|
|使いやすい。
|-
|Meld
|Windows/Linux
|x
|x
|x
|
|Linux系の標準。悪くない。
|-
|kdiff3
|Windows/Linux
|x
|x
|x
|
|開発停止。使えなくはない。
|-
|vimdiff
|x
|x
|x
|x
| -
|使いにくい。
|-
|Visual Studio Code
|x
|x
|x
|x
|x
|ディレクトリー比較は [[https://marketplace.visualstudio.com/items?itemName=moshfeu.compare-folders Compare Folders - Visual Studio Marketplace]] 拡張機能。 画像比較は [Image Preview] らしい。
|-
|Intellij IDARE
|x
| -
|x
|x
|x
|
|-
|Beyond Compare
|x
| -
|x
|x
|x
|
|-
|DiffImg
|Windows/Linux
|x
|x
|
|x
|
|-
|PerceptuallDiff
|x
|
| -
|
|x
|
|-
|PixelCompare
|
|
|x
|
|x
|
|}
DiffMerge一択になる。ファイルサイズも小さい。大きくても11 MB。


交互にしていい場合は簡単二重。引用符内に一重引用符を配置、一重引用符内に二重引用符を配置すればいい。
Visual Studio Codeが汎用的だから、こちらでいいかもしれない。


問題はこれがNGな場合。特にありがちなのが、JSONの生成。JSONの引用符は二重引用符のみ。一重引用符の中だと、二重引用符の変数展開が使用不能。外側を二重引用符にする必要がある。
==== DiffMerge ====
[https://note.com/modern_ferret431/n/nbb5061ddf08c mac で WinMerge |東京 AI 研究所]


二重引用符は、内部で変数展開が可能。この都合で、バックスラッシュ\によるエスケープが有効。
==== FileMerge ====
[https://reasonable-code.com/filemerge/ Mac純正のファイル差分確認ツール「FileMerge」が使いやすい - Reasonable Code]


基本的な方法。
[/Applications/Xcode.app]-右クリック-[Show content]-[Contents/Applications/FileMerge.app]


# 既存の一重/二重引用符などをバックスラッシュでエスケープ。
コマンドラインからだとopendiff。
# 全体を一重/二重引用符で囲む。


何かAwkの本か何かで、基本的な考え方の説明の記載があった気がする。
== Coding ==


[{"ke\y":"valu\e"}] を例として考える。
=== タイムゾーン ===
[https://qiita.com/dmikurube/items/15899ec9de643e91497c タイムゾーン呪いの書 #timezone - Qiita]


# {"ke\y":"valu\e"}
3文字形式は避けたほうが無難。
# エスケープ: {\"ke\\y\":\"valu\\e\"}
# 全体囲み: "{\"ke\\y\":\"valu\\e\"}"


これでOK。また何か考慮不足があればそのときに考える。
タイムゾーン名で判定する実装があるので、UTC-9なども避けたほうがいい。


ただ、元データに修正が必要なので、そのまま行きたい。ヒアドキュメント的なものが使えるならそれを使うのがいい。
tz databaseのAsia/Tokyoなどの確実性が高い。
=== Regular Expression ===
正規表現。重要。覚えにくいが重要なものをメモしておく。


例えば、シェルなら、catコマンドとコマンド置換で生テキストを使える。
後ろからマッチ。cが置換対象。
echo $(cat <<-'EOT'
{"ke\y":"valu\e"}
EOT
)
.envなどで使える技?いや使えない。.envではシンプルなコマンドしか使えず、ヒアドキュメントは使えない模様。


* [https://stackoverflow.com/questions/15637429/how-to-escape-double-quotes-in-json How to escape double quotes in JSON - Stack Overflow]
==== Case ====
* [https://stackoverflow.com/questions/64011248/how-to-handle-double-quotes-in-json-value python - How to handle double quotes in JSON value? - Stack Overflow]
/[^c]*$/: cより右端


JSONのvalue部分に適用したい場合。データの二重引用符をバックスラッシュでエスケープする。これはこうするしかない。JSONが二重引用符しか認めないから。
===== マッチの前後の挿入 =====
 
https:/vim.fandom.com/wiki/Power_of_g
基本的な考え方がある。
:g/GST_.*("/s/^/LOG(INFO) << "DEBUG";/r/
行頭・行末で引っ掛ける。


# JSON value用に二重引用符"を\"で置換。
===== 関数にログ =====
# \"がPHP/JavaScriptで二重引用符に扱いにならないように、\を\\に置換。
:%s/([^")]*)/) /([a-z]* /)*{/&/rLOG(INFO) << "/1";/r/g
# JSON項目の二重引用符"を\"で置換。
考慮するケース
# 全体を二重引用符"で囲む。
double currentTime() const override { return m_element->currentTime(); }


こういう感じ。JSONはawkでも任意の最終データで考える。途中にプログラミング言語でのパースがあるので、それを考慮する必要がある。
=== glob ===


=== ケース変換 ===
* [https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/functions/glob.html glob]
[https://stackoverflow.com/questions/63116039/camelcase-to-kebab-case javascript - camelCase to kebab-case - Stack Overflow]
* [https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/utilities/V3_chap02.html#tag_18_13 Shell Command Language]


キャメルケースをチェインケースにしたり、逆にしたりなどケース変換したいことがある。正規表現を駆使して実現する。
重要。正規表現とは似ているが異なる、パターンマッチング記法 (Pattern Matching Notation)。主に、globで採用されており、ディレクトリー・ファイルのマッチングで使われる。


=== encode ===
使用可能な記号は以下3個。以下の3文字は\でエスケープできる。
[https://www.sejuku.net/blog/25909 【PHP入門】URLエンコードする方法(urlencode) | 侍エンジニアブログ]


日本語や記号を他のコードに変換 (エンコード) する方式が何通りかある。把握しておくと役立つ。
* ?: 任意の1文字にマッチ。
* *: 任意の0以上の文字にマッチ。
* [: []内の1文字にマッチ。正規表現の各括弧と同じ。ただし、先頭の否定が^ではなく、!。


* パーセントエンコーディング/URLエンコード: URLで使用不能な文字を%16進数で連結。
ファイル名マッチ時には、追加で特殊なルールがある。
* UTF-8
* base64: 全データを「A-Z」「a-z」「0-9」「+」「/」の64文字で表現。文末に=を使うので実質は65文字。
* HTMLエンコード: HTMLで特殊な意味を持つ文字を&amp;lt;などに変換する。


==== Percent-encoding ====
.から始まるファイル名へのマッチには、.が必要。つまり、*?は先頭の.にはマッチしない。[!a] のような否定形の各括弧記法も.にはマッチしない。加えて、先頭の[.]もマッチするかは不定(unspecified)。


* [https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%BC%E3%82%BB%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0 パーセントエンコーディング - Wikipedia]
globで.ファイルを含めたい場合、工夫が必要 ([https://www.php.net/manual/ja/function.glob.php PHP: glob - Manual])
* [https://developer.mozilla.org/ja/docs/Glossary/Percent-encoding Percent-encoding (パーセントエンコーディング) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN]
.[!.]* *
* [https://datatracker.ietf.org/doc/html/rfc3986 RFC 3986 - Uniform Resource Identifier (URI): Generic Syntax]
上記のように.ファイルのマッチとそれ以外を指定する必要がある。


unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
<code>.[!.]*</code> は、<code>.</code>と<code>..</code>以外の.<code>.</code>始まりのファイルにマッチする。
上記文字はエンコードの対象外。


==== 英数変換 ====
<code>.*</code>を指定すると、<code>.</code>/<code>..</code>がマッチするので注意する。最近のシェルは、シェル側で気を利かせているようで、<code>.*</code>だと<code>.</code> /<code>..</code>はマッチしない。
[https://stackoverflow.com/questions/28110062/php-how-to-encode-all-characters-with-rawurlencode string - PHP How to encode all characters with rawurlencode - Stack Overflow]


変数名への変換などで、日本語や記号を英数字 [0-9a-zA-Z] に変換したいことがある。
=== 引用符のネスト ===
シェルやプログラミング言語で、文字列リテラルの表現などで、一重引用符'と二重引用符"を使う。


こういう目的だと%エンコーディングが適している。
JSON作成や変数展開などで、これらをネストさせたいことがある。その基本的な考え方を整理する。


ただし、一部の記号を許可しているので、自前で変換する。
交互にしていい場合は簡単二重。引用符内に一重引用符を配置、一重引用符内に二重引用符を配置すればいい。
function encode_all($str) {
    $hex = unpack('H*', $str);
    return preg_replace('~..~', '%$0', strtoupper($hex[1]));
}
$str = 'big ƒüßchen';
print_r(encode_all($str));


==== Term ====
問題はこれがNGな場合。特にありがちなのが、JSONの生成。JSONの引用符は二重引用符のみ。一重引用符の中だと、二重引用符の変数展開が使用不能。外側を二重引用符にする必要がある。
紛らわしい用語がある。


* ミドルウェア: 名前通り中間のソフトウェア。DBやアプリケーションサーバーなどが該当。単独で動作が重要なポイント ([https://sackle.co.jp/blog/detail/1248-2 ミドルウェアとは何か?代表的な製品や使用例とあわせて解説! - サックルMAGAZINE]、[https://system-kanji.com/posts/middleware-development ミドルウェアとは?アプリ・システム開発との関係・仕組み・役割・具体例を解説【2024年最新版】 | システム幹事])。
二重引用符は、内部で変数展開が可能。この都合で、バックスラッシュ\によるエスケープが有効。
* フレームワーク: 単体で動作しない。アプリ開発のテンプレート。Django/Ruby on Rails/Vue.jsなど ([https://www.pentasecurity.co.jp/pentapro/entry/framework_library 【3分ITキーワード】 フレームワークとライブラリの違いは? - ペンタPRO:ペンタセキュリティが提供するセキュリティ情報まとめサイト])。
* ライブラリー: 単体で動作しない。よく使われるコードの集まり。機能単位。jQuery/Numpy/matplotlib/Qtなど。


フレームワークの中にライブラリーも含めていいと思う。
基本的な方法。


==== Category ====
# 既存の一重/二重引用符などをバックスラッシュでエスケープ。
「[https://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E9%96%8B%E7%99%BA%E5%B7%A5%E7%A8%8B ソフトウェア開発工程 - Wikipedia]」
# 全体を一重/二重引用符で囲む。


ソフトウェアの分類、ページ分類時に役立つ。
何かAwkの本か何かで、基本的な考え方の説明の記載があった気がする。


* 言語
[{"ke\y":"valu\e"}] を例として考える。
* ツール: 静的解析、テスト、文書など。
* フレームワーク


MediaWikiのページ名は全体で固有が条件なので、言語名+分類名でページを作るといい。
# {"ke\y":"valu\e"}
# エスケープ: {\"ke\\y\":\"valu\\e\"}
# 全体囲み: "{\"ke\\y\":\"valu\\e\"}"


これでOK。また何か考慮不足があればそのときに考える。


* PHP language
ただ、元データに修正が必要なので、そのまま行きたい。ヒアドキュメント的なものが使えるならそれを使うのがいい。
* PHP tool
* PHP framework


==== 成功時連続継続処理 ====
例えば、シェルなら、catコマンドとコマンド置換で生テキストを使える。
一度の取得件数の上限が決まっていて、終了・失敗するまで取得を継続したいという処理がそれなりに発生する。
echo $(cat <<-'EOT'
{"ke\y":"valu\e"}
EOT
)
.envなどで使える技?いや使えない。.envではシンプルなコマンドしか使えず、ヒアドキュメントは使えない模様。


# 処理実行。
* [https://stackoverflow.com/questions/15637429/how-to-escape-double-quotes-in-json How to escape double quotes in JSON - Stack Overflow]
# 成功ならA、失敗なら終了。
* [https://stackoverflow.com/questions/64011248/how-to-handle-double-quotes-in-json-value python - How to handle double quotes in JSON value? - Stack Overflow]
# 処理実行。
# 成功ならA、失敗なら終了。


こういうパターン。いくつか実装方法があるが、while (true) のパターンが重複がなくてベストだと思う。
JSONのvalue部分に適用したい場合。データの二重引用符をバックスラッシュでエスケープする。これはこうするしかない。JSONが二重引用符しか認めないから。
        /*
        // 無限ループで終了条件でブレイク
        while (true) {
            // 処理実行
            if (失敗) {
                break;
            }
            成功時処理
        }
       
        // do while
        do {
            処理実行
            if (成功時) {}           
        } while ();
        // for (初期化; 継続判定・終了判定; 成功時式) {
            処理実行
        }
        */
do-whileは成功・終了判定を2回書く必要がある。


forだと成功処理を式でしか書けない。成功処理を関数や即時実行関数式などで書くなら悪くはないし、ベストになりえる。
基本的な考え方がある。


いや、成功時処理内の処理の結果次第で反復の終了条件などが追加で入るならNGになる。なので、やっぱりwhile(true)が無難。コード行数もそんなに変わらない。
# JSON value用に二重引用符"を\"で置換。
# \"がPHP/JavaScriptで二重引用符に扱いにならないように、\を\\に置換。
# JSON項目の二重引用符"を\"で置換。
# 全体を二重引用符"で囲む。
 
こういう感じ。JSONはawkでも任意の最終データで考える。途中にプログラミング言語でのパースがあるので、それを考慮する必要がある。
 
=== ケース変換 ===
[https://stackoverflow.com/questions/63116039/camelcase-to-kebab-case javascript - camelCase to kebab-case - Stack Overflow]
 
キャメルケースをチェインケースにしたり、逆にしたりなどケース変換したいことがある。正規表現を駆使して実現する。
 
=== encode ===
[https://www.sejuku.net/blog/25909 【PHP入門】URLエンコードする方法(urlencode) | 侍エンジニアブログ]


これにさらに初回だけ、ヘッダーの取得、書き込み処理などが発生する場合、初回だけループの外でやるのがきれいだろうか?初回処理が2回登場することになるけれど。
日本語や記号を他のコードに変換 (エンコード) する方式が何通りかある。把握しておくと役立つ。


offsetなどで初回の判定が反復内でできるから、それで分けるのがいいか?
* パーセントエンコーディング/URLエンコード: URLで使用不能な文字を%16進数で連結。
        $offset = 0;
* UTF-8
        while (true) {
* base64: 全データを「A-Z」「a-z」「0-9」「+」「/」の64文字で表現。文末に=を使うので実質は65文字。
            $currentReturnCode = $service->sendRequest(Raku2Config::API_TYPE_CSV_EXPORT, Raku2Config::CONFIG_API_URL_MULTI_API, [
* HTMLエンコード: HTMLで特殊な意味を持つ文字を&amp;lt;などに変換する。
                json_encode([
 
                    'dbSchemaId' => $table_info['dbSchemaId'],
==== Percent-encoding ====
                    'offset' => $offset,
 
                    'limit' => $limit,
* [https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%BC%E3%82%BB%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0 パーセントエンコーディング - Wikipedia]
                ])
* [https://developer.mozilla.org/ja/docs/Glossary/Percent-encoding Percent-encoding (パーセントエンコーディング) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN]
            ]);
* [https://datatracker.ietf.org/doc/html/rfc3986 RFC 3986 - Uniform Resource Identifier (URI): Generic Syntax]
 
            $response = $service->getApiResultJson();
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
            // 終了条件: 戻り値が成功以外、か応答本体が1行 (ヘッダーのみ) の時。
上記文字はエンコードの対象外。
            if (($currentReturnCode !== Raku2Config::EXIT_SUCCESS) || (substr_count($response, "\n") <= 1)) break;
 
==== 英数変換 ====
            // 2回目からはヘッダー除去して書き込み。
[https://stackoverflow.com/questions/28110062/php-how-to-encode-all-characters-with-rawurlencode string - PHP How to encode all characters with rawurlencode - Stack Overflow]
            $start = strpos($response, "\n") + 1;
 
            $flat = FILE_APPEND;
変数名への変換などで、日本語や記号を英数字 [0-9a-zA-Z] に変換したいことがある。
            if ($offset === 0) {
                $start = $flag = 0;
                $path = stream_get_meta_data($fp = tmpfile())['uri'];
            }
            file_put_contents($path, substr($response, $start), $flag);
            $offset += $limit;
            sleep(3);
        }


        for ($offset = 0;
こういう目的だと%エンコーディングが適している。
            ($currentReturnCode === Raku2Config::EXIT_SUCCESS) && (substr_count($response, "\n") > 1);
            (function() use (&$offset, $limit, $response) {
                // 2回目からはヘッダー除去して書き込み。
                $start = strpos($response, "\n") + 1;
                $flag = FILE_APPEND;
                if ($offset === 0) {
                    $start = $flag = 0;
                    $path = stream_get_meta_data($fp = tmpfile())['uri'];
                }
                file_put_contents($path, substr($response, $start), $flag);
                $offset += $limit;
                sleep(3);
            })()
        ) {
            $currentReturnCode = $service->sendRequest(Raku2Config::API_TYPE_CSV_EXPORT, Raku2Config::CONFIG_API_URL_MULTI_API, [
                json_encode([
                    'dbSchemaId' => $table_info['dbSchemaId'],
                    'offset' => $offset,
                    'limit' => $limit,
                ])
            ]);
            $response = $service->getApiResultJson();
        }


=== character ===
ただし、一部の記号を許可しているので、自前で変換する。
function encode_all($str) {
    $hex = unpack('H*', $str);
    return preg_replace('~..~', '%$0', strtoupper($hex[1]));
}
$str = 'big ƒüßchen';
print_r(encode_all($str));


==== BOM ====
==== Term ====
UTF-8のBOM
紛らわしい用語がある。
\xef\xbb\xbf
 
この文字を先頭につけるとUTF-8のBOMになる。
* ミドルウェア: 名前通り中間のソフトウェア。DBやアプリケーションサーバーなどが該当。単独で動作が重要なポイント ([https://sackle.co.jp/blog/detail/1248-2 ミドルウェアとは何か?代表的な製品や使用例とあわせて解説! - サックルMAGAZINE]、[https://system-kanji.com/posts/middleware-development ミドルウェアとは?アプリ・システム開発との関係・仕組み・役割・具体例を解説【2024年最新版】 | システム幹事])。
* フレームワーク: 単体で動作しない。アプリ開発のテンプレート。Django/Ruby on Rails/Vue.jsなど ([https://www.pentasecurity.co.jp/pentapro/entry/framework_library 【3分ITキーワード】 フレームワークとライブラリの違いは? - ペンタPRO:ペンタセキュリティが提供するセキュリティ情報まとめサイト])。
* ライブラリー: 単体で動作しない。よく使われるコードの集まり。機能単位。jQuery/Numpy/matplotlib/Qtなど。
 
フレームワークの中にライブラリーも含めていいと思う。
 
「[https://webbigdata.jp/what-is-ai/page-6804/page-8359/page-12091/ Pythonのモジュールとパッケージとライブラリとフレームワークの違い]」がわかりやすい。
 
フレームワークはライブラリーを含んでいる。ライブラリーで共通でいいと思う。
 
==== Category ====
「[https://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E9%96%8B%E7%99%BA%E5%B7%A5%E7%A8%8B ソフトウェア開発工程 - Wikipedia]」


=== Convert ===
ソフトウェアの分類、ページ分類時に役立つ。


==== IP/CIDR ====
* 言語
// JavaScript
* ツール: 静的解析、テスト、文書など。
<nowiki> </nowiki>  /**
* フレームワーク
<nowiki> </nowiki>    * サブネットマスクをIPアドレス形式 (x.x.x.x/255.255.255.0) からCIDR形式 (x.x.x.x/24) に変換する。
<nowiki> </nowiki>    * @param {string} ipaddress - IPアドレス文字列 (x.x.x.x/x.x.x.x形式)。
<nowiki> </nowiki>    */
<nowiki> </nowiki>  toCIDR(ipaddress) {
<nowiki> </nowiki>    const [address, mask] = ipaddress.split('/')
<nowiki> </nowiki>    const segments = mask.split('.')
<nowiki> </nowiki>    const CIDR = segments
<nowiki> </nowiki>      .map((e) => Number(e).toString(2))
<nowiki> </nowiki>      .join(<nowiki>''</nowiki>)
<nowiki> </nowiki>      .replace(/0*$/, <nowiki>''</nowiki>).length
<nowiki> </nowiki>    return address + '/' + CIDR
<nowiki> </nowiki>  },
<nowiki> </nowiki>  /**
<nowiki> </nowiki>    * サブネットマスクのCIDR形式 (24) をIPアドレス形式 (255.255.255.0)に変換する。
<nowiki> </nowiki>    * @param {number} cidr - ciderの数字。
<nowiki> </nowiki>    * @return {string} x.x.x.x形式のIPアドレス文字列。
<nowiki> </nowiki>    */
<nowiki> </nowiki>  cidrToIp(cidr) {
<nowiki> </nowiki>    const digit = 32
<nowiki> </nowiki>    const ip = ('1'.repeat(cidr) + '0'.repeat(digit)).substr(0, digit)
<nowiki> </nowiki>    return ip
<nowiki> </nowiki>      .match(/.{8}/g)
<nowiki> </nowiki>      .map((e) => parseInt(e, 2))
<nowiki> </nowiki>      .join('.')
<nowiki> </nowiki>  },


=== Algorithm ===
MediaWikiのページ名は全体で固有が条件なので、言語名+分類名でページを作るといい。


==== 再帰処理 ====
https://chatgpt.com/c/673d9bfe-2414-800b-9922-f94be6dbe950


配列の配列、オブジェクトのオブジェクトなど、再帰的な構造はけっこう遭遇する。
* PHP language
* PHP tool
* PHP framework


再帰関数で実装するほかに、スタックで処理する方法がある。
==== 成功時連続継続処理 ====
一度の取得件数の上限が決まっていて、終了・失敗するまで取得を継続したいという処理がそれなりに発生する。


再帰関数のほうが簡単に実装できるが、関数呼び出しのオーバーヘッドがある。ネスト10-100程度くらいなら問題ない。
# 処理実行。
 
# 成功ならA、失敗なら終了。
パフォーマンスや再帰中の細かい制御が必要なら、スタックが有利。ただし、実装がやや複雑。
# 処理実行。
# 成功ならA、失敗なら終了。


最初は再帰関数で実装して、後でボトルネックになったらスタックというのも手。
こういうパターン。いくつか実装方法があるが、while (true) のパターンが重複がなくてベストだと思う。
        /*
        // 無限ループで終了条件でブレイク
        while (true) {
            // 処理実行
            if (失敗) {
                break;
            }
            成功時処理
        }
       
        // do while
        do {
            処理実行
            if (成功時) {}           
        } while ();
        // for (初期化; 継続判定・終了判定; 成功時式) {
            処理実行
        }
        */
do-whileは成功・終了判定を2回書く必要がある。


https://chatgpt.com/c/6745228f-8b20-800b-8a41-bdaece8c03f5
forだと成功処理を式でしか書けない。成功処理を関数や即時実行関数式などで書くなら悪くはないし、ベストになりえる。


再帰関数とスタックの他に、JSONなどの文字列にシリアライズして、文字列処理で対応するという手もある。
いや、成功時処理内の処理の結果次第で反復の終了条件などが追加で入るならNGになる。なので、やっぱりwhile(true)が無難。コード行数もそんなに変わらない。


JSONPath/XPathなどの方法もあるが、基本的には外部ライブラリーが必要。
これにさらに初回だけ、ヘッダーの取得、書き込み処理などが発生する場合、初回だけループの外でやるのがきれいだろうか?初回処理が2回登場することになるけれど。


シンプルなケース以外は、再帰関数で処理したほうが結局シンプルな感じがする。
offsetなどで初回の判定が反復内でできるから、それで分けるのがいいか?
        $offset = 0;
        while (true) {
            $currentReturnCode = $service->sendRequest(Raku2Config::API_TYPE_CSV_EXPORT, Raku2Config::CONFIG_API_URL_MULTI_API, [
                json_encode([
                    'dbSchemaId' => $table_info['dbSchemaId'],
                    'offset' => $offset,
                    'limit' => $limit,
                ])
            ]);
            $response = $service->getApiResultJson();
            // 終了条件: 戻り値が成功以外、か応答本体が1行 (ヘッダーのみ) の時。
            if (($currentReturnCode !== Raku2Config::EXIT_SUCCESS) || (substr_count($response, "\n") <= 1)) break;
            // 2回目からはヘッダー除去して書き込み。
            $start = strpos($response, "\n") + 1;
            $flat = FILE_APPEND;
            if ($offset === 0) {
                $start = $flag = 0;
                $path = stream_get_meta_data($fp = tmpfile())['uri'];
            }
            file_put_contents($path, substr($response, $start), $flag);
            $offset += $limit;
            sleep(3);
        }


=== Other ===
        for ($offset = 0;
 
            ($currentReturnCode === Raku2Config::EXIT_SUCCESS) && (substr_count($response, "\n") > 1);
==== コメントの著者名 ====
            (function() use (&$offset, $limit, $response) {
https://chatgpt.com/c/67469d8d-7e64-800b-b82d-8c74f4e13c08
                // 2回目からはヘッダー除去して書き込み。
                $start = strpos($response, "\n") + 1;
                $flag = FILE_APPEND;
                if ($offset === 0) {
                    $start = $flag = 0;
                    $path = stream_get_meta_data($fp = tmpfile())['uri'];
                }
                file_put_contents($path, substr($response, $start), $flag);
                $offset += $limit;
                sleep(3);
            })()
        ) {
            $currentReturnCode = $service->sendRequest(Raku2Config::API_TYPE_CSV_EXPORT, Raku2Config::CONFIG_API_URL_MULTI_API, [
                json_encode([
                    'dbSchemaId' => $table_info['dbSchemaId'],
                    'offset' => $offset,
                    'limit' => $limit,
                ])
            ]);
            $response = $service->getApiResultJson();
        }


GNU socialのソースコードのコメントに著者名が大量にあった鬱陶しい。
=== character ===


大規模プロジェクトになると、編集者が膨大になる。VCSに任せて、本文には記載しなくていいと思う。
==== BOM ====
UTF-8のBOM
\xef\xbb\xbf
この文字を先頭につけるとUTF-8のBOMになる。


git blameで行単位で編集者が分かる。
=== Convert ===


== UML ==
==== IP/CIDR ====
// JavaScript
<nowiki> </nowiki>  /**
<nowiki> </nowiki>    * サブネットマスクをIPアドレス形式 (x.x.x.x/255.255.255.0) からCIDR形式 (x.x.x.x/24) に変換する。
<nowiki> </nowiki>    * @param {string} ipaddress - IPアドレス文字列 (x.x.x.x/x.x.x.x形式)。
<nowiki> </nowiki>    */
<nowiki> </nowiki>  toCIDR(ipaddress) {
<nowiki> </nowiki>    const [address, mask] = ipaddress.split('/')
<nowiki> </nowiki>    const segments = mask.split('.')
<nowiki> </nowiki>    const CIDR = segments
<nowiki> </nowiki>      .map((e) => Number(e).toString(2))
<nowiki> </nowiki>      .join(<nowiki>''</nowiki>)
<nowiki> </nowiki>      .replace(/0*$/, <nowiki>''</nowiki>).length
<nowiki> </nowiki>    return address + '/' + CIDR
<nowiki> </nowiki>  },
<nowiki> </nowiki>  /**
<nowiki> </nowiki>    * サブネットマスクのCIDR形式 (24) をIPアドレス形式 (255.255.255.0)に変換する。
<nowiki> </nowiki>    * @param {number} cidr - ciderの数字。
<nowiki> </nowiki>    * @return {string} x.x.x.x形式のIPアドレス文字列。
<nowiki> </nowiki>    */
<nowiki> </nowiki>  cidrToIp(cidr) {
<nowiki> </nowiki>    const digit = 32
<nowiki> </nowiki>    const ip = ('1'.repeat(cidr) + '0'.repeat(digit)).substr(0, digit)
<nowiki> </nowiki>    return ip
<nowiki> </nowiki>      .match(/.{8}/g)
<nowiki> </nowiki>      .map((e) => parseInt(e, 2))
<nowiki> </nowiki>      .join('.')
<nowiki> </nowiki>  },


=== Tool ===
=== Algorithm ===
https://chatgpt.com/c/67441feb-d004-800b-96fd-0d9b04ffc628


* デスクトップ
==== 再帰処理 ====
** StarUML
https://chatgpt.com/c/673d9bfe-2414-800b-9922-f94be6dbe950
** ArgoUML
** UMLet
* クラウド
** Lucidchart: 有料。
** Creately: 有料。
** diagrams.net: モデルじゃない。


UmbrelloとModelioはそれらと比較して何がよかったのだっけ?
配列の配列、オブジェクトのオブジェクトなど、再帰的な構造はけっこう遭遇する。


=== Umbrello ===
再帰関数で実装するほかに、スタックで処理する方法がある。


==== Problem ====
再帰関数のほうが簡単に実装できるが、関数呼び出しのオーバーヘッドがある。ネスト10-100程度くらいなら問題ない。
altなどの重なり順番、アクティブの下になっちゃう


optの条件が表示されない。
パフォーマンスや再帰中の細かい制御が必要なら、スタックが有利。ただし、実装がやや複雑。


=== Modelio ===
最初は再帰関数で実装して、後でボトルネックになったらスタックというのも手。


==== クラス図 ====
https://chatgpt.com/c/6745228f-8b20-800b-8a41-bdaece8c03f5
* 汎化 (generalization): 実線白矢印。継承。
* 実現 (realization): 点線矢印。interfaceの継承。
* 集約: 白ひし形。
* コンポジション: 黒ひし形。子が単体で存在できない場合。親と生存期間が同一の場合。
* 関連: 実線矢印。メソッド内インスタンスなど。
* 依存: 点線矢印。引数やローカル変数、返却値。


=== Design ===
再帰関数とスタックの他に、JSONなどの文字列にシリアライズして、文字列処理で対応するという手もある。


==== Atomic Design ====
JSONPath/XPathなどの方法もあるが、基本的には外部ライブラリーが必要。


* [https://atomicdesign.bradfrost.com/chapter-2/ Atomic Design Methodology | Atomic Design by Brad Frost]
シンプルなケース以外は、再帰関数で処理したほうが結局シンプルな感じがする。
* [https://zenn.dev/bizlink/articles/b5c8985af8407a Atomic Designの概念]


最近のUIのコンポーネントの組み方。UIコンポーネントを粒度に分けて、ディレクトリー分けして流用するという考え方。
=== Other ===


* atoms: 原子。これ以上分割不能な最小単位。input/label/buttonなど。
==== コメントの著者名 ====
* molecules: 分子。atomsを組み合わせたり、atomsに多少修正したもの。入力フォーム、ナビゲーション、カードなど。
https://chatgpt.com/c/67469d8d-7e64-800b-b82d-8c74f4e13c08
* organisms: 有機体。分子+アルファ。入力フォーム+ヘッダーなど。複数の分子。
* templates: テンプレート。複数の有機体。ヘッダー、メイン、フッターなど。
* pages: ページ。テンプレートを使用したページ。


==== インターフェイスと抽象クラス ====
GNU socialのソースコードのコメントに著者名が大量にあった鬱陶しい。
[https://qiita.com/nogson/items/e6575d6617f854ed6e25 PHPでインターフェイスと抽象クラスを使う #PHP - Qiita]


* インターフェイスは、クラスに複数実装できるが、抽象クラスは1つしか継承できない。→不特定のクラスで、共通のメソッドを定義したい場合。
大規模プロジェクトになると、編集者が膨大になる。VCSに任せて、本文には記載しなくていいと思う。
* インターフェイスは、実装のあるメソッドを持つことができないが、抽象クラスは、実装のあるメソッドを持つことができる。→抽象クラスは、複数のクラスの、共通処理の中に、一部違う処理が入る場合、プロパティーが必要な場合などに使用する。


インターフェイス
git blameで行単位で編集者が分かる。


* メソッド宣言のみ。
== UML ==
* static/constの場合に限定して、メソッド定義、定数もOK。


==== Config class ====
=== Tool ===
https://chatgpt.com/c/67441feb-d004-800b-96fd-0d9b04ffc628


* [https://softwareengineering.stackexchange.com/questions/197272/best-practice-for-creating-a-global-config-class-used-by-numerous-components c++ - Best practice for creating a 'global' config class used by numerous components - Software Engineering Stack Exchange]
[https://www.quora.com/What-are-the-best-UML-tools-for-macOS What are the best UML tools for macOS? - Quora]
* [https://softwareengineering.stackexchange.com/questions/386212/best-way-to-provide-configuration-parameters-for-objects-far-away-from-the-start Best way to provide configuration parameters for objects far away from the starting point - Software Engineering Stack Exchange]
* [https://softwareengineering.stackexchange.com/questions/114924/config-class-struct-pattern-or-anti-pattern-alternatives?newreg=b46538fc865f46b08f6bf06d317925bf design - Config Class/Struct: Pattern or Anti-Pattern? Alternatives? - Software Engineering Stack Exchange]
* [https://softwareengineering.stackexchange.com/questions/441985/best-practice-design-pattern-for-working-with-a-config-file json - Best practice/design pattern for working with a config file - Software Engineering Stack Exchange]


アプリケーションの設定を管理するクラスの設計方法。いくつか方法があり、議論がある。「[https://softwareengineering.stackexchange.com/questions/386212/best-way-to-provide-configuration-parameters-for-objects-far-away-from-the-start Best way to provide configuration parameters for objects far away from the starting point - Software Engineering Stack Exchange]」で特によく議論されている。
* デスクトップ
** StarUML
** ArgoUML
** UMLet
** OmniGraffle
** edraw: 有料。
** Umbrello
** Modelio
* クラウド
** Visual Paradigm
** Lucidchart: 有料。
** Creately: 有料。
** diagrams.net: モデルじゃない。
*その他
**PlantUML


# シングルトン/グローバル変数: ただし、テストなどで並列アクセスが必要な場合に困ることがあるらしい。
UmbrelloとModelioはそれらと比較して何がよかったのだっけ?
# DI/設定クラス引数: これがよく支持されている。テストしやすいなど。グローバル変数への参照を渡すようなイメージ。ただし、依存性の伝播のように、上から下に設定を渡す際に、関係ない大量の設定を渡すことがあったりする。


2のDIが最近の主流。引数で値渡し相当にすれば、並列アクセス時も無影響。伝播の問題は設計の問題。
Eclipse Papyrusが動作するならこれがいい。Eclipseは安定しているから、これのプラグインで動作するなら信頼できるだろう。


メソッドをmain関数で呼び出すことを想定して、必要なものだけ渡るようにして、余計なものは削除する。上位・下位の関係を明確にすれば、渡すだけのパラメーターを排除できる。
papyrusは一度試してダメだった気がするが。


==== do-while/if ====
=== Umbrello ===
複雑なif文と相性がいい。


for whileの無限ループで最後にbreakでも同じか
==== Problem ====
do {
altなどの重なり順番、アクティブの下になっちゃう
  if (true) break;
} while(false);
if文が複雑な場合、do-whileで囲んで、breakでスキップできる。gotoに近い。


==== GoF ====
optの条件が表示されない。
基本的に、具象クラスを使わずに、インターフェイスや抽象クラスを使ってインスタンスを生成するというのが、共通する基本パターン。


これにより、いろんなケースに同じコードで対応できる。
=== Modelio ===


===== Factory Methodパターン =====
==== クラス図 ====
[https://blog.ecbeing.tech/entry/2021/01/20/114000 なぜあんなに難しい?Factory Methodパターン - ecbeing labs(イーシービーイング・ラボ)]
* 汎化 (generalization): 実線白矢印。継承。
* 実現 (realization): 点線矢印。interfaceの継承。
* 集約: 白ひし形。
* コンポジション: 黒ひし形。子が単体で存在できない場合。親と生存期間が同一の場合。
* 関連: 実線矢印。メソッド内インスタンスなど。
* 依存: 点線矢印。引数やローカル変数、返却値。


コンストラクターの代わりに、インスタンスを生成 (工場=factory) となるメソッドを使うから、FactoryMethodパターン。
=== Papyrus ===
[https://eclipse.dev/papyrus/download.html Papyrus Dowloads]


引数の内容に応じて、異なるクラスを作成する。
[https://eclipse.dev/papyrus/documentation.html Papyrus Documentation]


ただ、Factory Methodパターンを採用すると、コード量が増えて複雑になる。
==== Tutorial ====
公式の[A slide-ware tutorial on Eclipse Papyrus usage for starters (2010-10-01)]を参考に基本的な使い方を学ぶ。


複雑でややこしいだけなので、基本的に使わなくてよいと思う。
[File]-[New]-[Papyrus prooject]


==== Naming ====
これでプロジェクトを作ると、以下が [Project Explorer] に作られる。


===== camelCase =====
* <project name>
https://gnusocial.jp/notice/7694551
** <project name>
*** di: ツールメタデータ。モデル作成のエントリーポイント。
*** notation: 画像データ。
*** uml: UMLモデルデータ。


!it 命名規則のキャメルケース。これ英語前提です。関数名に英語以外を使うと破綻します。
このdiをダブルクリックして描画を開始する。


getキーバリュー()みたいな関数の定義。日本語ですると境界がわからなくなるので、getキー_バリューみたいにアンダーバーで区切ったほうが分かりやすい。なるほど…
1個のプロジェクトでいろんな図に対応していて、モデルを流用できる形になっている。悪くない。これを使う。


===== getMyVariable() vs myVariable() =====
画面構成


* [https://stackoverflow.com/questions/3532828/php-methods-getmyvariable-vs-myvariable naming conventions - PHP methods: getMyVariable() vs myVariable() - Stack Overflow]
# Project explorer
* [https://stackoverflow.com/questions/139427/which-coding-convention-to-follow-for-php Which Coding convention to follow for PHP? - Stack Overflow]
# Model explorer: 一番重要。ここでモデル全体をツリーベースで管理する。
# Outline view: アウトライン
# Main toolber: ツールバー。
# Perspective: Model explorerの内容を使って作図する領域。
# Property view: モデルのエディター画面。


getterとsetterの命名規則。
Model explorerがPapyrusの本質。ここでクラスとかインタラクションを定義しておいて、この定義をperspectiveの作図に使うイメージ。


getVar()にするか、Var()にするか。C++だと後者のパターンがあったりする。getを省略できるので、省スペースになる。
クラス図やシーケンス図もModel explorerに所属していて、好きなだけ作れる。[New diagram]から作れる。


ただ、コード補完で探しやすさがちょっと変わる。getを前置したほうがわかりやすいか。
[New Child] でいくつか重要なモデルがある。


===== namePrefixed() vs prefixedName() =====
* Package: ディレクトリ・フォルダーみたいなもの。これで他のモデルをまとめて整理できる。
https://chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85
* Interaction: シーケンス図表現用のモデル。
* Class: クラス。Interactionの型だったりする。UMLのベースで非常に重要。


名詞+修飾語 (形容詞) の場合のメソッドの命名規則。name+修飾語が複数ある場合name+修飾語がいい。オブジェクト指向でnameをオブジェクトとして扱う形に近い。name.methodみたいな。
==== Class ====


例えば、nameMax、nameMinのような場合は後ろのほうが都合がいい。ただ、こういう場合はそもそもnameをオブジェクトにしてname.max()、name.min()にしたほうがいいという説がある。
===== 属性表示 =====
クラス図にクラスモデルを配置しても、プロパティーやメソッドが表示されない。


そうではないならば、getPrefixedName()などが自然。getQueryString()など。StringQueryではない。
右クリック-[Filters] で制御できる。


PHPでは以下のような命名規則が好まれる。
* [Synchronized with Model] を選ぶと同期されて全部表示される。基本はこれで、一部だけ表示したい場合にここを外すのだろうと思う。
* [Show/Hide Contents] で表示可否をチェックボックスで選べる。


* 動詞+修飾対象=getPrefixedName/isPrefixed()
=== Design ===
* 修飾対象+状態/修飾語=prefixdName


getPrefixedNameがいいか。後置修飾にしたいならば、そもそもオブジェクト+メソッドにすることを検討する。
==== Atomic Design ====


===== map =====
* [https://atomicdesign.bradfrost.com/chapter-2/ Atomic Design Methodology | Atomic Design by Brad Frost]
連想配列とかハッシュ、オブジェクトなどでキーバリュー形式のデータ構造を扱うことがある。そういう変数の命名規則。
* [https://zenn.dev/bizlink/articles/b5c8985af8407a Atomic Designの概念]
 
最近のUIのコンポーネントの組み方。UIコンポーネントを粒度に分けて、ディレクトリー分けして流用するという考え方。


<code>map_[key]_[value]</code> のような形式にすると、キーとバリューが何を意味するか分かってわかりやすい。
* atoms: 原子。これ以上分割不能な最小単位。input/label/buttonなど。
* molecules: 分子。atomsを組み合わせたり、atomsに多少修正したもの。入力フォーム、ナビゲーション、カードなど。
* organisms: 有機体。分子+アルファ。入力フォーム+ヘッダーなど。複数の分子。
* templates: テンプレート。複数の有機体。ヘッダー、メイン、フッターなど。
* pages: ページ。テンプレートを使用したページ。


===== array/foreach =====
==== インターフェイスと抽象クラス ====
[https://qiita.com/nogson/items/e6575d6617f854ed6e25 PHPでインターフェイスと抽象クラスを使う #PHP - Qiita]


* [https://wiki.senooken.jp/PHP#Name_2 PHP - senooken JP Wiki]
* インターフェイスは、クラスに複数実装できるが、抽象クラスは1つしか継承できない。→不特定のクラスで、共通のメソッドを定義したい場合。
* https://chatgpt.com/c/6747aee4-ab64-800b-88d7-940a5c4201bf
* インターフェイスは、実装のあるメソッドを持つことができないが、抽象クラスは、実装のあるメソッドを持つことができる。→抽象クラスは、複数のクラスの、共通処理の中に、一部違う処理が入る場合、プロパティーが必要な場合などに使用する。


foreach系のfor文ではキーとバリューを変数に格納して反復する。ファイルや配列に対して行うことが多い。
インターフェイス
foreach (table as $row => $line)
その際の変数名は、上記のように$row/$lineにすると、行番号と行の値がはっきりしてわかりやすい。


いいえ。これは問題がある。ネストした場合などに命名規則を維持できない。
* メソッド宣言のみ。
* static/constの場合に限定して、メソッド定義、定数もOK。


* 配列、コレクション類: 複数形があるなら複数形。困ったらListの接尾辞。
==== Config class ====
* 反復時。キーバリュー形式の場合、単数形_key/_value。valueだけの場合、単数形。また、_valueは単数形でもいいかもしれない。


上記の命名規則だとわかりやすい。
* [https://softwareengineering.stackexchange.com/questions/197272/best-practice-for-creating-a-global-config-class-used-by-numerous-components c++ - Best practice for creating a 'global' config class used by numerous components - Software Engineering Stack Exchange]
$rows = [[]];
* [https://softwareengineering.stackexchange.com/questions/386212/best-way-to-provide-configuration-parameters-for-objects-far-away-from-the-start Best way to provide configuration parameters for objects far away from the starting point - Software Engineering Stack Exchange]
foreach ($rows as $row_key => $row_value) {
* [https://softwareengineering.stackexchange.com/questions/114924/config-class-struct-pattern-or-anti-pattern-alternatives?newreg=b46538fc865f46b08f6bf06d317925bf design - Config Class/Struct: Pattern or Anti-Pattern? Alternatives? - Software Engineering Stack Exchange]
  foreach ($row_value as $column_key => $column_value) {}
* [https://softwareengineering.stackexchange.com/questions/441985/best-practice-design-pattern-for-working-with-a-config-file json - Best practice/design pattern for working with a config file - Software Engineering Stack Exchange]
}
foreach ($row_list as $row_key => $row) {
    foreach ($row as $column_key => $column) {
    }
}
foreach ($rows as $row_index => $row_value) {
  foreach ($row_value as $column_index => $column_value) {
  }
}
value部分に単数形を使うと、検索時にkey部分もヒットして、作業しにくいかもしれない。基本はkey/valueの接尾辞がよいと感じる。


もっというなら、接尾辞の文字数が揃うので、keyよりindexのほうがよいかもしれない。ただ、indexは添え字の数字の意味合いが強いので、やっぱりkey/valueでいいか。
アプリケーションの設定を管理するクラスの設計方法。いくつか方法があり、議論がある。「[https://softwareengineering.stackexchange.com/questions/386212/best-way-to-provide-configuration-parameters-for-objects-far-away-from-the-start Best way to provide configuration parameters for objects far away from the starting point - Software Engineering Stack Exchange]」で特によく議論されている。


===== Function argument order =====
# シングルトン/グローバル変数: ただし、テストなどで並列アクセスが必要な場合に困ることがあるらしい。
関数の引数は入力、変更、出力の順番にする。理由はこの順番で使うから。<blockquote><nowiki>https://social.senooken.jp/notice/67270</nowiki>
# DI/設定クラス引数: これがよく支持されている。テストしやすいなど。グローバル変数への参照を渡すようなイメージ。ただし、依存性の伝播のように、上から下に設定を渡す際に、関係ない大量の設定を渡すことがあったりする。


うーん。今晩は,CODE COMPLETEでC言語の関数の引数の順番を調べたりしていて,勉強時間がないな…
2のDIが最近の主流。引数で値渡し相当にすれば、並列アクセス時も無影響。伝播の問題は設計の問題。


int func(入力,変更,出力)
メソッドをmain関数で呼び出すことを想定して、必要なものだけ渡るようにして、余計なものは削除する。上位・下位の関係を明確にすれば、渡すだけのパラメーターを排除できる。


この順番。理由は,この順番で使うから。
==== do-while/if ====
複雑なif文と相性がいい。


memcpyとかは例外が多い。
for whileの無限ループで最後にbreakでも同じか
do {
  if (true) break;
} while(false);
if文が複雑な場合、do-whileで囲んで、breakでスキップできる。gotoに近い。


x = bの語順からきているからとの憶測がある。
==== GoF ====
基本的に、具象クラスを使わずに、インターフェイスや抽象クラスを使ってインスタンスを生成するというのが、共通する基本パターン。


<nowiki>https://okwave.jp/qa/q4202225.html</nowiki></blockquote>
これにより、いろんなケースに同じコードで対応できる。


==== DB ====
===== Factory Methodパターン =====
[http://blog.tojiru.net/article/277021312.html PDOの真の力を開放する - PHPでデータベースを扱う(3): Architect Note]
[https://blog.ecbeing.tech/entry/2021/01/20/114000 なぜあんなに難しい?Factory Methodパターン - ecbeing labs(イーシービーイング・ラボ)]


DBアクセスのモデル化。行をクラスとすると扱いやすい模様。
コンストラクターの代わりに、インスタンスを生成 (工場=factory) となるメソッドを使うから、FactoryMethodパターン。


getterを作ったり、データの妥当性のチェックなどもできる。
引数の内容に応じて、異なるクラスを作成する。


select/insert/などはmapperでクラスとDB列名を対応付けて処理する。自前で実装する場合はこういうつくりがいいらしい。
ただ、Factory Methodパターンを採用すると、コード量が増えて複雑になる。


データベース関係のデザインパターンがいくつかある。
複雑でややこしいだけなので、基本的に使わなくてよいと思う。


* Active Record
==== Naming ====
* Data Mapper


===== Active Record pattern =====
===== camelCase =====
https://gnusocial.jp/notice/7694551


* [https://ja.wikipedia.org/wiki/Active_Record Active Record - Wikipedia]
!it 命名規則のキャメルケース。これ英語前提です。関数名に英語以外を使うと破綻します。
* [https://www.techscore.com/tech/Ruby/Rails/other/designpattern/ デザインパターンから見たActive Record | TECHSCORE(テックスコア)]


テーブルレコードに対応するクラスを用意して、そのクラス自体にDB操作もさせる。
getキーバリュー()みたいな関数の定義。日本語ですると境界がわからなくなるので、getキー_バリューみたいにアンダーバーで区切ったほうが分かりやすい。なるほど…


シンプルだが、複雑な操作が苦手。
===== getMyVariable() vs myVariable() =====


エンティティーがテーブルと密接なため、例えばテーブル構造が変わった場合に大量に修正必要。
* [https://stackoverflow.com/questions/3532828/php-methods-getmyvariable-vs-myvariable naming conventions - PHP methods: getMyVariable() vs myVariable() - Stack Overflow]
* [https://stackoverflow.com/questions/139427/which-coding-convention-to-follow-for-php Which Coding convention to follow for PHP? - Stack Overflow]


Ruby on Rails/Laravel+Eloquentなどで採用。
getterとsetterの命名規則。


===== Data Mapper pattern =====
getVar()にするか、Var()にするか。C++だと後者のパターンがあったりする。getを省略できるので、省スペースになる。
[https://gihyo.jp/dev/serial/01/ruby/0014 第14回 DataMapperの使い方 | gihyo.jp]


テーブルのレコードをクラスにするのはARと共通。
ただ、コード補完で探しやすさがちょっと変わる。getを前置したほうがわかりやすいか。


ただし、DB操作用のクラスを用意してそちらでDB操作する。
===== namePrefixed() vs prefixedName() =====
https://chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85


その都合、1テーブルに2クラス必要。
名詞+修飾語 (形容詞) の場合のメソッドの命名規則。name+修飾語が複数ある場合name+修飾語がいい。オブジェクト指向でnameをオブジェクトとして扱う形に近い。name.methodみたいな。


User/UserMapperのような対応関係。
例えば、nameMax、nameMinのような場合は後ろのほうが都合がいい。ただ、こういう場合はそもそもnameをオブジェクトにしてname.max()、name.min()にしたほうがいいという説がある。


2クラス必要だが、テーブル構造が変わった場合でも基本はMapperで吸収できる。
そうではないならば、getPrefixedName()などが自然。getQueryString()など。StringQueryではない。


===== JOIN =====
PHPでは以下のような命名規則が好まれる。
Active RecordもData MapperもJOIN時の扱いが一番重要。単一エンティティーしか扱わないならどちらも同じ。


基本はエンティティーのプロパティーに持たせる感じ。
* 動詞+修飾対象=getPrefixedName/isPrefixed()
* 修飾対象+状態/修飾語=prefixdName


<blockquote>datamapperパターンでjoinする場合、エンティティーの扱いはどうなるの?
getPrefixedNameがいいか。後置修飾にしたいならば、そもそもオブジェクト+メソッドにすることを検討する。


`DataMapper`パターンで`JOIN`を行う場合、エンティティの扱いは設計次第ですが、いくつかの注意点があります。`DataMapper`パターンは、データベースのテーブルとエンティティの間にマッピングを行い、エンティティはドメインロジックを持ち、データベースアクセスの責務を持たないことが特徴です。そのため、`JOIN`の処理をどの層で行うかを慎重に設計する必要があります。
===== map =====
連想配列とかハッシュ、オブジェクトなどでキーバリュー形式のデータ構造を扱うことがある。そういう変数の命名規則。


以下、`JOIN`を行う際のエンティティの扱いと実装方法について解説します。
<code>map_[key]_[value]</code> のような形式にすると、キーとバリューが何を意味するか分かってわかりやすい。


### 1. マッパークラスでの`JOIN`実装
===== array/foreach =====


`JOIN`を伴う複雑なクエリが必要な場合、マッパーが直接`JOIN`を使って複数テーブルを組み合わせた結果を取得し、それを複数のエンティティとしてマッピングする方法があります。例えば、ユーザーと注文を持つシステムで、ユーザーとその注文を一緒に取得したい場合、`UserMapper`で`JOIN`を行い、結果セットを`User`と`Order`エンティティに分割してマッピングします。
* [https://wiki.senooken.jp/PHP#Name_2 PHP - senooken JP Wiki]
* https://chatgpt.com/c/6747aee4-ab64-800b-88d7-940a5c4201bf


```python
foreach系のfor文ではキーとバリューを変数に格納して反復する。ファイルや配列に対して行うことが多い。
foreach (table as $row => $line)
その際の変数名は、上記のように$row/$lineにすると、行番号と行の値がはっきりしてわかりやすい。


class UserMapper:
いいえ。これは問題がある。ネストした場合などに命名規則を維持できない。


    def find_user_with_orders(self, user_id):
* 配列、コレクション類: 複数形があるなら複数形。困ったらListの接尾辞。
* 反復時。キーバリュー形式の場合、単数形_key/_value。valueだけの場合、単数形。また、_valueは単数形でもいいかもしれない。


        sql = """
上記の命名規則だとわかりやすい。
 
$rows = [[]];
            SELECT * FROM users
foreach ($rows as $row_key => $row_value) {
 
  foreach ($row_value as $column_key => $column_value) {}
            JOIN orders ON users.id = orders.user_id
}
 
            WHERE users.id = %s
foreach ($row_list as $row_key => $row) {
    foreach ($row as $column_key => $column) {
    }
}
foreach ($rows as $row_index => $row_value) {
  foreach ($row_value as $column_index => $column_value) {
  }
}
value部分に単数形を使うと、検索時にkey部分もヒットして、作業しにくいかもしれない。基本はkey/valueの接尾辞がよいと感じる。


        """
もっというなら、接尾辞の文字数が揃うので、keyよりindexのほうがよいかもしれない。ただ、indexは添え字の数字の意味合いが強いので、やっぱりkey/valueでいいか。


        results = self.db.execute(sql, (user_id,))
===== Function argument order =====
関数の引数は入力、変更、出力の順番にする。理由はこの順番で使うから。<blockquote><nowiki>https://social.senooken.jp/notice/67270</nowiki>


       
うーん。今晩は,CODE COMPLETEでC言語の関数の引数の順番を調べたりしていて,勉強時間がないな…


        user = User(results[0]['user_id'], results[0]['user_name'])
int func(入力,変更,出力)


        orders = [Order(row['order_id'], row['product_name'], user) for row in results]
この順番。理由は,この順番で使うから。


        user.orders = orders
memcpyとかは例外が多い。


        return user
x = bの語順からきているからとの憶測がある。


```
<nowiki>https://okwave.jp/qa/q4202225.html</nowiki></blockquote>


この方法では、1つのSQLクエリで必要なデータをすべて取得し、エンティティのプロパティにそれぞれのデータを設定します。
==== DB ====
[http://blog.tojiru.net/article/277021312.html PDOの真の力を開放する - PHPでデータベースを扱う(3): Architect Note]


### 2. リポジトリでの集約
DBアクセスのモデル化。行をクラスとすると扱いやすい模様。


`JOIN`を使わず、各エンティティを個別に取得した後、リポジトリが集約の役割を担う方法もあります。リポジトリが各エンティティの`Mapper`を呼び出し、必要なエンティティ同士を関連付けることで`JOIN`を再現します。例えば、まず`UserMapper`でユーザー情報を取得し、次に`OrderMapper`で該当ユーザーの注文を取得してエンティティ間で関連付けます。
getterを作ったり、データの妥当性のチェックなどもできる。


```python
select/insert/などはmapperでクラスとDB列名を対応付けて処理する。自前で実装する場合はこういうつくりがいいらしい。


class UserRepository:
データベース関係のデザインパターンがいくつかある。


    def __init__(self, user_mapper, order_mapper):
* Active Record
* Data Mapper


        self.user_mapper = user_mapper
===== Active Record pattern =====


        self.order_mapper = order_mapper
* [https://ja.wikipedia.org/wiki/Active_Record Active Record - Wikipedia]
* [https://www.techscore.com/tech/Ruby/Rails/other/designpattern/ デザインパターンから見たActive Record | TECHSCORE(テックスコア)]


    def get_user_with_orders(self, user_id):
テーブルレコードに対応するクラスを用意して、そのクラス自体にDB操作もさせる。


        user = self.user_mapper.find(user_id)
シンプルだが、複雑な操作が苦手。


        orders = self.order_mapper.find_by_user_id(user_id)
エンティティーがテーブルと密接なため、例えばテーブル構造が変わった場合に大量に修正必要。


        user.orders = orders
Ruby on Rails/Laravel+Eloquentなどで採用。


        return user
===== Data Mapper pattern =====
[https://gihyo.jp/dev/serial/01/ruby/0014 第14回 DataMapperの使い方 | gihyo.jp]


```</blockquote>UserテーブルとOrderテーブルがあって、あるユーザーの注文一覧を取得したい場合を考える。
テーブルのレコードをクラスにするのはARと共通。


結局、user.ordersみたいな感じで、エンティティーに外部テーブルのレコードを配列で持たせるつくりになる。
ただし、DB操作用のクラスを用意してそちらでDB操作する。


クロス集計する場合は、users[0].orderみたいな感じ。メインのエンティティーのプロパティーに持たせる。フラットじゃないのでちょっと気持ち悪い。が、まあ構造としてこうなるのは順当。
その都合、1テーブルに2クラス必要。


方法として、1回のSQLで取得するか、それぞれのエンティティーを取得してマージするか。1回のSQLでやったほうが当然いい。
User/UserMapperのような対応関係。


==== Other ====
2クラス必要だが、テーブル構造が変わった場合でも基本はMapperで吸収できる。


===== 1対1-多対多 =====
===== JOIN =====
プログラミング言語でデータの関連付けをすることがある。
Active RecordもData MapperもJOIN時の扱いが一番重要。単一エンティティーしか扱わないならどちらも同じ。


1対1の場合、配列、連想配列のキーバリュー形式のデータがぴったり。
基本はエンティティーのプロパティーに持たせる感じ。


多対多の場合。これも配列。二次元配列で基本は0要素目など。
<blockquote>datamapperパターンでjoinする場合、エンティティーの扱いはどうなるの?
$array[][]


==== Project ====
`DataMapper`パターンで`JOIN`を行う場合、エンティティの扱いは設計次第ですが、いくつかの注意点があります。`DataMapper`パターンは、データベースのテーブルとエンティティの間にマッピングを行い、エンティティはドメインロジックを持ち、データベースアクセスの責務を持たないことが特徴です。そのため、`JOIN`の処理をどの層で行うかを慎重に設計する必要があります。


===== レガシープロジェクトの立て直し =====
以下、`JOIN`を行う際のエンティティの扱いと実装方法について解説します。
https://chatgpt.com/c/67481a93-adc0-800b-81c4-20d763133002


1. 現状分析
### 1. マッパークラスでの`JOIN`実装


(1) ソフトウェアの動作確認
`JOIN`を伴う複雑なクエリが必要な場合、マッパーが直接`JOIN`を使って複数テーブルを組み合わせた結果を取得し、それを複数のエンティティとしてマッピングする方法があります。例えば、ユーザーと注文を持つシステムで、ユーザーとその注文を一緒に取得したい場合、`UserMapper`で`JOIN`を行い、結果セットを`User`と`Order`エンティティに分割してマッピングします。


現在の環境でアプリケーションを動作させる。
```python


どの部分が機能していて、どこが問題かを確認する。
class UserMapper:


必要であればエラーログを確認する。
    def find_user_with_orders(self, user_id):


(2) 依存関係の調査
        sql = """


アプリケーションのライブラリやフレームワークのバージョンを調査。
            SELECT * FROM users


サポートが終了しているもの、互換性が失われたものを特定。
            JOIN orders ON users.id = orders.user_id


(3) コードベースの状態評価
            WHERE users.id = %s


コードの品質 (可読性、設計、テストカバレッジ) を確認。
        """


セキュリティリスクを特定する (例えば、脆弱性が放置されていないか)
        results = self.db.execute(sql, (user_id,))


2. 計画立案
       


(1) ゴール設定
        user = User(results[0]['user_id'], results[0]['user_name'])


具体的な目標を設定 (例: パフォーマンス改善、保守性向上、セキュリティ強化)
        orders = [Order(row['order_id'], row['product_name'], user) for row in results]


(2) 優先順位の決定
        user.orders = orders


どの機能を維持し、どの機能を削除または置き換えるか決定。
        return user


ユーザーに直接影響を与える部分を優先。
```


(3) リスク評価とバックアップ
この方法では、1つのSQLクエリで必要なデータをすべて取得し、エンティティのプロパティにそれぞれのデータを設定します。


修正に伴うリスクを評価し、現行システムのバックアップを取得。
### 2. リポジトリでの集約


3. 環境整備
`JOIN`を使わず、各エンティティを個別に取得した後、リポジトリが集約の役割を担う方法もあります。リポジトリが各エンティティの`Mapper`を呼び出し、必要なエンティティ同士を関連付けることで`JOIN`を再現します。例えば、まず`UserMapper`でユーザー情報を取得し、次に`OrderMapper`で該当ユーザーの注文を取得してエンティティ間で関連付けます。


(1) 開発環境のモダナイズ
```python


ローカル環境やコンテナ (Docker) を用意してテストを容易にする。
class UserRepository:


CI/CD パイプラインの整備。
    def __init__(self, user_mapper, order_mapper):


(2) 依存関係の更新
        self.user_mapper = user_mapper


サポートされていないライブラリやフレームワークをアップグレードまたは置き換える。
        self.order_mapper = order_mapper


(3) セキュリティの確保
    def get_user_with_orders(self, user_id):


古いOSSの脆弱性を修正。
        user = self.user_mapper.find(user_id)


HTTPSの導入、認証強化、インプット検証など。
        orders = self.order_mapper.find_by_user_id(user_id)


4. コードのモダナイズ
        user.orders = orders


(1) リファクタリング
        return user


レガシーコードをよりモダンで可読性の高いコードに変換。
```</blockquote>UserテーブルとOrderテーブルがあって、あるユーザーの注文一覧を取得したい場合を考える。


デザインパターンを適用して保守性を向上。
結局、user.ordersみたいな感じで、エンティティーに外部テーブルのレコードを配列で持たせるつくりになる。


(2) テストの追加
クロス集計する場合は、users[0].orderみたいな感じ。メインのエンティティーのプロパティーに持たせる。フラットじゃないのでちょっと気持ち悪い。が、まあ構造としてこうなるのは順当。


ユニットテスト、統合テストを導入。
方法として、1回のSQLで取得するか、それぞれのエンティティーを取得してマージするか。1回のSQLでやったほうが当然いい。


既存の機能が壊れないことを確認するための自動化されたテスト。
==== Other ====


(3) フロントエンド/バックエンドの分離
===== 1対1-多対多 =====
プログラミング言語でデータの関連付けをすることがある。


必要に応じてモノリシック構造を分離し、モダンなアーキテクチャ (SPA、Microservices など) に移行。
1対1の場合、配列、連想配列のキーバリュー形式のデータがぴったり。


5. 機能拡張とデプロイ
多対多の場合。これも配列。二次元配列で基本は0要素目など。
$array[][]


(1) 新しい機能の追加
==== Project ====


必要に応じて、現代のニーズに合った新機能を実装。
===== レガシープロジェクトの立て直し =====
https://chatgpt.com/c/67481a93-adc0-800b-81c4-20d763133002


(2) 運用環境でのテスト
1. 現状分析


新しい環境で徹底的にテストし、問題がないことを確認。
(1) ソフトウェアの動作確認


(3) 本番環境にデプロイ
現在の環境でアプリケーションを動作させる。


ロールバック計画を準備しつつ、安全にデプロイ。
どの部分が機能していて、どこが問題かを確認する。


6. 継続的改善
必要であればエラーログを確認する。


(1) モニタリングの導入
(2) 依存関係の調査


エラーログやパフォーマンスを監視し、迅速に対応できる仕組みを導入。
アプリケーションのライブラリやフレームワークのバージョンを調査。


(2) 定期的なアップデート
サポートが終了しているもの、互換性が失われたものを特定。


フレームワークやライブラリを継続的に更新し、レガシー化を防ぐ。
(3) コードベースの状態評価


(3) コミュニティへの貢献
コードの品質 (可読性、設計、テストカバレッジ) を確認。


OSSとしての性質を活かし、変更内容をコミュニティに共有することでフィードバックを得る。
セキュリティリスクを特定する (例えば、脆弱性が放置されていないか)。


このプロセスを通じて、安定した動作を保ちながら徐々に近代化することが可能です。特に、「現状分析」と「環境整備」をしっかり行うことで、後続の作業がスムーズになります。
2. 計画立案


== AI ==
(1) ゴール設定


=== 対話AI ===
具体的な目標を設定 (例: パフォーマンス改善、保守性向上、セキュリティ強化)。


==== List ====
(2) 優先順位の決定
[https://notepm.jp/blog/24168 【2024年版】対話型AIサービスおすすめ11選を徹底比較!チャットボットとの違い・メリット・課題・選び方なども紹介 - NotePM]


いろいろある。
どの機能を維持し、どの機能を削除または置き換えるか決定。
{| class="wikitable"
|+
!Name
!
!
!
|-
|Bing
|
|
|
|-
|Perplexity AI
|
|
|
|-
|ChatGPT
|
|
|
|-
|Google Gemini
|
|
|
|}


==== ChatGPT ====
ユーザーに直接影響を与える部分を優先。
 
(3) リスク評価とバックアップ
 
修正に伴うリスクを評価し、現行システムのバックアップを取得。
 
3. 環境整備
 
(1) 開発環境のモダナイズ
 
ローカル環境やコンテナ (Docker) を用意してテストを容易にする。
 
CI/CD パイプラインの整備。
 
(2) 依存関係の更新


===== Plan =====
サポートされていないライブラリやフレームワークをアップグレードまたは置き換える。
[https://openai.com/chatgpt/ ChatGPT | OpenAI]


Free/Plusの2のプランがある。
(3) セキュリティの確保
{| class="wikitable"
|+
!
!Free
!Plus
|-
|金額 [USD/月]
|0
|20
|-
|機能
|基本
|アーリーアクセス
|-
|エンジン
|GPT-4o mini
|GPT-4/GPT-4o/GPT-4o mini
|-
|制限
| -
|GPT-4oの5倍以上のメッセージ送信
|-
|その他
| -
|データ分析、ファイルアップロード、ビジョン、Webブラウジング
|-
|画像生成
| -
|DALL-E
|}
送信可能なメッセージ数、エンジン、画像生成などが大きな違いだろう。


===== Account =====
古いOSSの脆弱性を修正。
公式サイトにアカウントの意味の説明がない。しかたないので、ChatGPTに質問。<blockquote>ChatGPTに会員登録する意味は何ですか?


HTTPSの導入、認証強化、インプット検証など。


ChatGPTに会員登録する主な利点はいくつかあります。
4. コードのモダナイズ


1. **パーソナライズされた体験**: 登録すると、あなたの好みや過去のやり取りに基づいて、よりカスタマイズされた応答が得られます。
(1) リファクタリング


2. **履歴の管理**: 過去のチャット履歴を保存し、いつでも見返すことができるため、情報の確認が簡単になります。
レガシーコードをよりモダンで可読性の高いコードに変換。


3. **新機能へのアクセス**: 登録ユーザーは新しい機能やアップデートを優先的に利用できる場合があります。
デザインパターンを適用して保守性を向上。


4. **プレミアム機能**: 一部のサービスでは、会員登録をすることで、より高度な機能やサポートが提供されることがあります。
(2) テストの追加


5. **セキュリティとプライバシー**: アカウントを持つことで、データの管理やプライバシーの設定をより細かく調整できます。
ユニットテスト、統合テストを導入。


興味があれば、ぜひ登録を検討してみてください!他に質問があればお知らせください。</blockquote>自分の過去の質問の履歴を見れるだけでも便利かも。
既存の機能が壊れないことを確認するための自動化されたテスト。


===== 方法 =====
(3) フロントエンド/バックエンドの分離


====== 質問の分割 ======
必要に応じてモノリシック構造を分離し、モダンなアーキテクチャ (SPA、Microservices など) に移行。
https://chatgpt.com/c/673bdc0d-e0e0-800b-a22b-4fa19e64476c


Q. chatgptで質問するとき、連続して質問すると、同じURLで複数の質問が表示される。リロードして質問を分けたほうがいいのか?
5. 機能拡張とデプロイ


A. どちらでも問題ない。が、質問が関連しているなら同じチャットで継続したほうがいい。直前の質問も文脈を考慮できる。完全に話が異なるなら分けたほうが後で整理したり、URLを共有したときにわかりやすい。
(1) 新しい機能の追加


===== 感想 =====
必要に応じて、現代のニーズに合った新機能を実装。


====== 2024-11-14 Thu ======
(2) 運用環境でのテスト
https://gnusocial.jp/notice/7806505<blockquote>[[/gnusocial.jp/group/32/id|!it]] [[/gnusocial.jp/group/28/id|!ai]] 業務でPHPの開発作業をしていて、ChatGPTを使いだして便利に感じています。検索エンジンの代わりに使っています。


例えば、「laravel eloquentでリレーション先のテーブルの主キー名の取得方法は?」と質問します。
新しい環境で徹底的にテストし、問題がないことを確認。


[[/chatgpt.com/c/67354314-fbdc-800b-a4e4-65f96d1a8fb2|https://chatgpt.com/c/67354314-fbdc-800b-a4e4-65f96d1a8fb2]]
(3) 本番環境にデプロイ


getRelatedというややマニアックなメソッドを教えてくれます[eloquent getrelated] で検索してもなかなかたどり着けないです。
ロールバック計画を準備しつつ、安全にデプロイ。


こういう検索エンジンで検索しにくい質問で便利だなと思います。
6. 継続的改善


検索エンジンで検索すると、的外れな情報も大量にヒットします。対話AIはそのごみの混ざった検索結果を分析した結果をコンパクトに返してくれます。対話AI使わなくても、検索エンジンで時間かければわかりますが、大幅に時間短縮できます。
(1) モニタリングの導入


大量の凡人健常者が取り組んだ方法論として決まりきったものは、記憶の問題、ただの神経衰弱です。こういうのを検索エンジンの改良版としてAIに任せるのはいい使い方だと思います。
エラーログやパフォーマンスを監視し、迅速に対応できる仕組みを導入。


個人的に、ただの知識、事実は重要度高くないと思いますが、一般社会では評価する側の頭が悪いので、これが重宝されます。
(2) 定期的なアップデート


同僚や先輩に聞くより対話AIのほうがよほど頭いいです。話すことないです。聞くほうが時間の無駄なので。凡人はどんどん要らなくなります。
フレームワークやライブラリを継続的に更新し、レガシー化を防ぐ。


一方、私みたいなキチガイのデータは少ないので、検索エンジンやAIに聞いても出てこないです。世界で自分だけのオリジナルに専念するのがたぶんいいです。</blockquote>
(3) コミュニティへの貢献


====== 2024-11-19 Tue ======
OSSとしての性質を活かし、変更内容をコミュニティに共有することでフィードバックを得る。
https://gnusocial.jp/notice/7867350<blockquote>[[/gnusocial.jp/group/28/id|!ai]] ChatGPTが検索エンジンの改良版としてやっぱり便利。さっきこういう質問しました。


phpのメソッド名で、英単語の修飾語は前と後ろどちらがいい?例えば、namePrefixed()とprefixedName()のどちらがいい? [[/chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85|https://chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85]]
このプロセスを通じて、安定した動作を保ちながら徐々に近代化することが可能です。特に、「現状分析」と「環境整備」をしっかり行うことで、後続の作業がスムーズになります。


私はこのレベルの細かい疑問がすぐ浮かぶのです。これを人間にきくと、頓珍漢な回答だったり、そもそも回答してもらえないし、何ならこういう質問した私がなぜかキチガイ扱いされて、微妙な雰囲気になって、質問できなくなって、ストレスが溜まって、居づらくなって早期退職になるんです。意味不明です。ただの質問にお気持ちの配慮とか面倒なので。
== AI ==


この間、 [[/misskey-square.net/users/9g2o6eycu3|@yuriha]] に突っ込まれた件も、たぶん対話AIとお互い会話したほうが有意義だったんじゃないかとすら思います。相手も私に突っ込む前に対話AIと会話したほうが自分の主張の自己矛盾、頓珍漢さに気づけたんじゃないかとすら思えます。私が突っ込んでまーた私がキチガイ扱いされるのも回避されます。対話AIからの客観的な指摘なら、同じ内容であっても、キチガイの私が言うより納得しやすいでしょう?同じ内容なら対話AIのほうが凡人健常者にとっては、信じ込みやすいでしょ?
=== 対話AI ===


対話AIだとお気持ちの配慮いらないし、当たり前ですけど、キチガイ扱いされることもないので、快適です。元々対話AIには懐疑的でしたが、どちらかというと私のようなキチガイが凡人健常者の知識を拝借するためにあるような印象を持ちます。
==== List ====
[https://notepm.jp/blog/24168 【2024年版】対話型AIサービスおすすめ11選を徹底比較!チャットボットとの違い・メリット・課題・選び方なども紹介 - NotePM]


検索エンジンでも調べることはできますが、めちゃくちゃ時間かかるんです。自分で複数の意見をみつけて、頭の中で比較検討して整理するので。これを一瞬でやってくれるのが楽。途中のデータ整理、目視は単純作業に近いのです。他のことに頭使えます。
いろいろある。
 
{| class="wikitable"
もはや技術とか、ただの暗記の神経衰弱は別にいらないです。一般企業の上長とか、士業のように、単純知識でマウント取るタイプの仕事はこれで確かに駆逐されます。どうせ対話AIのほうが賢いのだから。知識量で勝てるわけないです。全世界の情報の集積結果なんだから。
|+
 
!Name
凡人健常者の知識を拝借して、世界でだれにも真似できないキチガイ部分に専念できます。GNU socialの開発もこれでいけると思います。</blockquote>
!
 
!
== VCS ==
!
 
|-
=== List ===
|Bing
Comparison of issue-tracking systems - Wikipedia <nowiki>https://en.wikipedia.org/wiki/Comparison_of_issue-tracking_systems</nowiki>
|
|
|
|-
|Perplexity AI
|
|
|
|-
|ChatGPT
|
|
|
|-
|Google Gemini
|
|
|
|}


BTS。GitHubみたいな。PHP製の以下がよさそう。
==== ChatGPT ====


* Tuleap
===== Plan =====
* Phabricator/Phorge: 共用サーバー不能。
[https://openai.com/chatgpt/ ChatGPT | OpenAI]
* MantisBT
* FusionForge
* GLPI
* Faveo Helpdesk
* [https://sourcehut.org/ sourcehut - the hacker's forge]: Python製。FSF推奨。
* Fossil


VCSとの統合状況がまちまち。
Free/Plusの2のプランがある。
 
{| class="wikitable"
phorgeがダメだったので、Mantis/Fossil/sourcehutあたりが共用サーバーで検討可能か。
|+
 
!
https://chatgpt.com/c/674f8938-8590-800b-9a4c-f1ec04fc5869
!Free
 
!Plus
他に以下がある。
|-
 
|金額 [USD/月]
* Gitea
|0
* Cgit
|20
* Gitlab
|-
* SourceHut: Python
|機能
* GitBucket: Java
|基本
|アーリーアクセス
|-
|エンジン
|GPT-4o mini
|GPT-4/GPT-4o/GPT-4o mini
|-
|制限
| -
|GPT-4oの5倍以上のメッセージ送信
|-
|その他
| -
|データ分析、ファイルアップロード、ビジョン、Webブラウジング
|-
|画像生成
| -
|DALL-E
|}
送信可能なメッセージ数、エンジン、画像生成などが大きな違いだろう。


Gitlabは共用サーバーで可能なのか?無理。cgitの他、gogsもある?
===== Account =====
公式サイトにアカウントの意味の説明がない。しかたないので、ChatGPTに質問。<blockquote>ChatGPTに会員登録する意味は何ですか?


CGIで利用可能なもの。


* Cgit: gitの出力を見れるだけ。issueはない。
ChatGPTに会員登録する主な利点はいくつかあります。
* Gitweb: cgit同様。
* ViewGit:
* Kallithea: 有力。[https://kallithea-scm.org/ Kallithea]。WSGI。CGI未対応。
他に。


* rhodecode: CGIではない。Python+WSGI
1. **パーソナライズされた体験**: 登録すると、あなたの好みや過去のやり取りに基づいて、よりカスタマイズされた応答が得られます。
* [[wikipedia:Category:Project_management_software|Category:Project management software - Wikipedia]]


「[https://jp.quora.com/Python%E3%81%AF%E4%BA%BA%E6%B0%97%E3%81%AE%E8%A8%80%E8%AA%9E%E3%81%A7%E3%81%99-%E3%81%97%E3%81%8B%E3%81%97-%E3%81%9D%E3%81%AE%E5%89%B2%E3%81%ABPython%E3%81%8C%E6%B0%97%E8%BB%BD%E3%81%AB%E5%88%A9%E7%94%A8%E3%81%A7 Pythonは人気の言語です。しかし、その割にPythonが気軽に利用できるレンタルサーバーは少ない感じがします。何故、レンタルサーバーはPythonの利用に消極的なのですか? - Quora]」にあるように、WSGIをCGIにすることもできるがいまいちらしい。
2. **履歴の管理**: 過去のチャット履歴を保存し、いつでも見返すことができるため、情報の確認が簡単になります。


他。
3. **新機能へのアクセス**: 登録ユーザーは新しい機能やアップデートを優先的に利用できる場合があります。


https://chatgpt.com/c/67546eda-20ac-800b-b37f-7e8954c128f5
4. **プレミアム機能**: 一部のサービスでは、会員登録をすることで、より高度な機能やサポートが提供されることがあります。


* GNU Savannah/savane
5. **セキュリティとプライバシー**: アカウントを持つことで、データの管理やプライバシーの設定をより細かく調整できます。
* Bugzilla: 課題管理のみ。
* Trac: CGI OK。
* Roundup ([https://roundup.sourceforge.io/ Roundup Issue Tracker - Roundup 2.4.0 documentation]): 課題管理のみ?
* Debbugs


savaneはメンテナンスされていないので、Trac一択。redmineはCGIで動作しない。
興味があれば、ぜひ登録を検討してみてください!他に質問があればお知らせください。</blockquote>自分の過去の質問の履歴を見れるだけでも便利かも。


=== Git ===
===== 方法 =====


==== Commit ====
====== 質問の分割 ======
https://chatgpt.com/c/673bdc0d-e0e0-800b-a22b-4fa19e64476c


===== マージコミット後のコミット追加 =====
Q. chatgptで質問するとき、連続して質問すると、同じURLで複数の質問が表示される。リロードして質問を分けたほうがいいのか?
マージコミット後に次の開発作業を始めることが多い。が、直後の初回のコミットを追加したい場合困る。


git rebase -iにすると、コミットが残るから。編集はできるが、その直前にコミットの追加ができない。マージコミットは扱いが特殊で直接rebaseで編集できない。
A. どちらでも問題ない。が、質問が関連しているなら同じチャットで継続したほうがいい。直前の質問も文脈を考慮できる。完全に話が異なるなら分けたほうが後で整理したり、URLを共有したときにわかりやすい。


しかたないので、該当コミットでブランチを作成して、コミット。その後、既存の修正ブランチをrebaseでそのコミットの後にくっつける。これでいける。
===== 感想 =====


===== コミットオプション =====
====== 2024-11-14 Thu ======
[https://git-scm.com/docs/git-commit Git - git-commit Documentation]
https://gnusocial.jp/notice/7806505<blockquote>[[/gnusocial.jp/group/32/id|!it]] [[/gnusocial.jp/group/28/id|!ai]] 業務でPHPの開発作業をしていて、ChatGPTを使いだして便利に感じています。検索エンジンの代わりに使っています。


コミットメッセージ指定のためのオプションがある。
例えば、「laravel eloquentでリレーション先のテーブルの主キー名の取得方法は?」と質問します。


* -m|--message <message>: コミットを文字列で指定。複数指定可能で、その場合段落で区切ってくれる。2行目以後を書きたい場合などで使う。
[[/chatgpt.com/c/67354314-fbdc-800b-a4e4-65f96d1a8fb2|https://chatgpt.com/c/67354314-fbdc-800b-a4e4-65f96d1a8fb2]]
* -C|--reuse-message <commit>: 指定したコミットのコミット情報を再使用する。
* -c|--reedit-message <commit>: -Cの同じだが、編集画面を表示してコミットメッセージを編集して再使用する。
* -F|--file=<file>: 指定したファイルをコミットメッセージに使う。-を指定すると標準入力を使う。


基本は-m。-mの複数指定。
getRelatedというややマニアックなメソッドを教えてくれます[eloquent getrelated] で検索してもなかなかたどり着けないです。


===== 過去コミットのメールアドレスの変更 =====
こういう検索エンジンで検索しにくい質問で便利だなと思います。


* [https://www.git-tower.com/learn/git/faq/change-author-name-email How can I change the author (name / email) of a commit? | Learn Version Control with Git]
検索エンジンで検索すると、的外れな情報も大量にヒットします。対話AIはそのごみの混ざった検索結果を分析した結果をコンパクトに返してくれます。対話AI使わなくても、検索エンジンで時間かければわかりますが、大幅に時間短縮できます。
* [https://zenn.dev/flyingbarbarian/articles/241627cae5988a Gitのcommitの名前やメールアドレスを過去からまとめて変更する]


単一コミットのメールアドレスを指定する場合、commitに--authorを指定する。
大量の凡人健常者が取り組んだ方法論として決まりきったものは、記憶の問題、ただの神経衰弱です。こういうのを検索エンジンの改良版としてAIに任せるのはいい使い方だと思います。
git commit --author="John Doe <john@doe.org>"
--amendと併用することで、過去コミットも変更できる。


数が少ないなら、rebase -iで1個ずつamendする。数が多いならfilter-branch。
個人的に、ただの知識、事実は重要度高くないと思いますが、一般社会では評価する側の頭が悪いので、これが重宝されます。


===== 第一コミットの変更 =====
同僚や先輩に聞くより対話AIのほうがよほど頭いいです。話すことないです。聞くほうが時間の無駄なので。凡人はどんどん要らなくなります。


* [https://dev.classmethod.jp/articles/git-rebase-from-root/ [Git] 最初のコミットを含めてrebase -iする方法 | DevelopersIO]
一方、私みたいなキチガイのデータは少ないので、検索エンジンやAIに聞いても出てこないです。世界で自分だけのオリジナルに専念するのがたぶんいいです。</blockquote>
* [https://git-scm.com/docs/git-rebase Git - git-rebase Documentation]


通常、第一コミットはammend以外では変更できない。
====== 2024-11-19 Tue ======
https://gnusocial.jp/notice/7867350<blockquote>[[/gnusocial.jp/group/28/id|!ai]] ChatGPTが検索エンジンの改良版としてやっぱり便利。さっきこういう質問しました。


rebase --root [branch] でブランチの第一コミットも参照して改変可能。
phpのメソッド名で、英単語の修飾語は前と後ろどちらがいい?例えば、namePrefixed()とprefixedName()のどちらがいい? [[/chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85|https://chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85]]


===== マージコミットの打ち消し =====
私はこのレベルの細かい疑問がすぐ浮かぶのです。これを人間にきくと、頓珍漢な回答だったり、そもそも回答してもらえないし、何ならこういう質問した私がなぜかキチガイ扱いされて、微妙な雰囲気になって、質問できなくなって、ストレスが溜まって、居づらくなって早期退職になるんです。意味不明です。ただの質問にお気持ちの配慮とか面倒なので。
マージコミットは扱いがやや特殊。
git revert -m 1 マージコミット
git reset --hard HEAD~1 # マージコミット前
どちらか。


==== stash ====
この間、 [[/misskey-square.net/users/9g2o6eycu3|@yuriha]] に突っ込まれた件も、たぶん対話AIとお互い会話したほうが有意義だったんじゃないかとすら思います。相手も私に突っ込む前に対話AIと会話したほうが自分の主張の自己矛盾、頓珍漢さに気づけたんじゃないかとすら思えます。私が突っ込んでまーた私がキチガイ扱いされるのも回避されます。対話AIからの客観的な指摘なら、同じ内容であっても、キチガイの私が言うより納得しやすいでしょう?同じ内容なら対話AIのほうが凡人健常者にとっては、信じ込みやすいでしょ?


===== 復元 =====
対話AIだとお気持ちの配慮いらないし、当たり前ですけど、キチガイ扱いされることもないので、快適です。元々対話AIには懐疑的でしたが、どちらかというと私のようなキチガイが凡人健常者の知識を拝借するためにあるような印象を持ちます。
[https://qiita.com/generosity-naman/items/237338f8fe5b7e3b9a76 Git Stashの復元: 誤って削除されたスタッシュの復元方法 #Git-Stash - Qiita]


git stash drop実行時に、削除したコミットのSHA1が表示される。
検索エンジンでも調べることはできますが、めちゃくちゃ時間かかるんです。自分で複数の意見をみつけて、頭の中で比較検討して整理するので。これを一瞬でやってくれるのが楽。途中のデータ整理、目視は単純作業に近いのです。他のことに頭使えます。


そのSHA1をapplyで指定すれば、取り込める。
もはや技術とか、ただの暗記の神経衰弱は別にいらないです。一般企業の上長とか、士業のように、単純知識でマウント取るタイプの仕事はこれで確かに駆逐されます。どうせ対話AIのほうが賢いのだから。知識量で勝てるわけないです。全世界の情報の集積結果なんだから。
git stash apply [stash_hash]


===== リモート =====
凡人健常者の知識を拝借して、世界でだれにも真似できないキチガイ部分に専念できます。GNU socialの開発もこれでいけると思います。</blockquote>
[https://qiita.com/mather314/items/a1536c52a2eb0426b2b5 gitの不要なブランチを消すコマンド #Git - Qiita]
git fetch -p/--prune
リモートの削除済みブランチをローカルに同期する。


===== リモートの最新タグ =====
== Shell ==
https:/stackoverflow.com/questions/20734181/how-to-get-list-of-latest-tags-in-remote-git


git ls-remote --tag --sort=taggerdate
=== Shell Command Language ===


date関係のsortはオブジェクトへのアクセスが必要なので、ローカルにないとダメとか。
==== Compound Commands ====
[https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/utilities/V3_chap02.html#tag_18_09_04 Shell Command Language]


https:/git-scm.com/docs/git-ls-remote.html
===== Case Conditional Construct =====
case word in
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac


https:/stackoverflow.com/questions/10649814/get-last-git-tag-from-a-remote-repo-without-cloning
* 未マッチで終了ステータス0。
* pattern部分: シェル展開が有効。他はglob。
* |でOR検索相当。
* 最後のパターンの;;は省略可能。if文のようにも使える。
* 全パターンの捕捉は最後に*。空でもマッチする。?は最低1文字必要。


git rev-listでいけそう。
BREでは未対応な|のORマッチに対応しているのが最大の特徴。文法なのでコマンドを実行せず早い。grepを使わずにできるだけこちらを使ったほうがいい。


https:/gist.github.com/rponte/fdc0724dd984088606b0
=== ワイルドカード ===
ワイルドカードで.始まりのファイルをマッチさせたい。


===== 差分ファイル抽出 =====
以下ならマッチするが、ブレース展開 (brace expansion) はPOSIX shでは使えなかった気がする。
情報源: [https://qiita.com/kaminaly/items/28f9cb4e680deb700833 gitで差分ファイルを抽出する #Git - Qiita]。
echo {.*,*}


git archiveとgit diffを組み合わせる。
=== BOM ===
git archive --format=zip --prefix=root/ HEAD `git diff --diff-filter=d --name-only HEAD^ HEAD` -o archive.zip
[https://stackoverflow.com/questions/3127436/adding-bom-to-utf-8-files unicode - Adding BOM to UTF-8 files - Stack Overflow]
ただし、この方法はファイル数がARG_MAX以下の場合だけ。ファイル数が多い場合だめ。


git diff --name-onlyで一覧を出力させて、1個ずつcp -pで階層を維持してコピーするしかないかも?
ExcelでUTF-8ファイルを開けるように、UTF-8のBOMをファイルにつけたい。
printf '\xEF\xBB\xBF' > with_bom.txt
上記コードでBOMを最初に書き込んで、後は追記する。


:
=== awk ===
mkdir -p archive
[https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/ The Open Group Base Specifications Issue 7]
git diff --name-only new_base 44765_upgrade-base-version | xargs -i cp -p --parent "{}" archive/


===== core.autocrlf =====
==== 変数 ====
<blockquote>warning: in the working copy of 'docker/README.md', LF will be replaced by CRLF the next time Git touches it</blockquote>Windowsでは改行にCR+LFを使うが、mac/LinuxはLFのみ。これの違いの処理のための設定がcore.autoclrlf


* true=コミット時にCRLFをLFに自動変換。チェックアウト時に逆。Windows向けの設定。
===== 特別 =====
* false=変換しない。
* NF: 列数。列の全表示などで使う基本的で重要な変数。
* input=コミット時にCRLFをLFに自動変換のみ。mac/Linux向け。Windowsではチェックアウト時にCRLFになるが、mac/LinuxはLFになる。
* NR: 行番号。


わかりにくい。基本はfalseで良いと思われる。
===== スコープ =====
[http://www.fukano.jp/study_of_awk/basic/basic08.htm 変数のスコープ]


===== gitkの文字化け対策 =====
関数の仮引数のみ、ローカル変数扱いで、それ以外はグローバル変数。
[https://www.pistolfly.com/weblog/2010/02/gitk.html gitkのエンコーディングを設定する - Pistolfly]


gitkはシステムのデフォルトエンコーディングで表示しようとするので、文字エンコーディングを指定しておく。
==== 文/statement ====
git config --global gui.encoding utf-8


===== ファイル名などの文字化け対策 =====
* actions
[https://qiita.com/kumazo/items/2169e1ee7be278f82b94 Git for Windows で日本語を使いたい #Vim - Qiita]
** if/else
git config --global core.quotepath false
** while/do...while/for
git config --global gui.encoding utf-8
** break/continue
** delete
** next
** exit
* output
** print
** printf


===== 改名と修正 =====
==== 関数 ====


* [https://qiita.com/yukimura1227/items/fbb076db61a2e43a32e3 gitでrename&modifyしたファイルのログを追跡できるようにしたい場合 #Git - Qiita]
===== 組込関数 =====
* [https://zenn.dev/yoichi/articles/how-git-handles-renaming Gitはファイルのリネームをどう扱うか]


改名と修正を同時にすると、改名を検知できない。
* Arithmetic
 
** atan2
-Mオプションを指定すると、類似度で同時も検知できる。が、基本はリネーム・改名と修正は別コミットにしたほうがよさそう。
** cos
 
** sin
===== 差分無視 =====
** exp
[https://qiita.com/odekekepeanuts/items/8a056b87c9e481e07e57 git diffの--ignoreオプションにおけるスペース、タブ、改行の扱いを理解する #Git - Qiita]
** log
 
** sqrt
-wでインデント違いを無視してくれる。
** int
 
** rand
===== squash =====
** srand
squashすると、squash対象コミットが、対象の直前のコミットに含められる。
* String
 
** gsub
===== gitignore =====
** index
[https://git-scm.com/docs/gitignore/en Git - gitignore Documentation]
** length
 
** match
====== Format ======
** split
記述方法を整理する。
** sprintf
 
** sub
* 空行は無視。
** substr
* #始まりの行はコメント扱い。
** tolower
* 終端スペースは無視。
** toupper
* !接頭辞はパターン否定。つまり、除外ではなく含める。以前除外された一致を再び含める。ただし、親ディレクトリーが除外されている場合、以下のファイルは含められない。パフォーマンス上の理由。順番に注意する。
* I/O
* /はディレクトリー区切りとして使用。先頭、中間、末尾で登場する。
** close
** 先頭と中間の/は相対パスを意味する。
** getline
** それ以外、末尾の/と/なしの場合、現在以下のディレクトリーにもマッチする。
** system
** 末尾が/で終わる場合、ディレクトリーのみに一致。/がない場合、ディレクトリーとファイルの両方に一致。
* *は/以外にマッチ。?は/以外の任意の1文字にマッチ。[a-zA-Z] の範囲記法も使用可能。fnmatch(3) FNM_PATHNAMEフラグのパス名展開に準じる。
* **は特殊な意味がある。
** **/=全ディレクトリー。**/fooは配下の全fooにマッチ。**/foo/barはfoo以下の全barにマッチ。
** /**=配下のすべてにマッチ。
** a/**/b=a/b a/x/b a/x/y/bのすべてにマッチ。
 
後は特に明記がないが、上から順番に評価されて、最後のマッチが優先されるので、記述の順番に注意する。


反転の!と/の扱いに特に注意が必要。
print/printfは関数ではなく、statement/文扱い。


先頭スラッシュをつけないと、再帰的になる。
==== ヘッダー出力、列別最大長さ出力。 ====
    $ cat .gitignore
<nowiki>awk -F, '{if(NR==1) print $0} {for(i=1; i<=NF; ++i){if (line[i] < length($i)) line[i] = length($i)}} END {for (i=1; i<=NF; ++i) {printf line[i]","}}' data/101542.csv</nowiki>
    # ディレクトリ foo/bar 以外のすべてを除外
    /*
    !/foo
    /foo/*
    !/foo/bar


====== 空ディレクトリーの維持 ======
==== CSV ====
[https://stackoverflow.com/questions/115983/how-do-i-add-an-empty-directory-to-a-git-repository How do I add an empty directory to a Git repository? - Stack Overflow]
[https://qiita.com/ko1nksm/items/19407c1c53cbbc50569a シェルスクリプトの実験のために作った POSIX 準拠 awk 実装の CSVパーサー (RFC4180対応) #ShellScript - Qiita]<syntaxhighlight lang="awk" line="1">
# csvparser.awk


gitは空ディレクトリーを履歴管理できない。何かファイルが必要。
## Usage
# awk -f csvparser.awk data.csv


logなど維持したい空ディレクトリーに、以下の内容の.gitignoreを置く。
# CSV の論理的な一行毎に呼び出されるコールバック関数(サンプル)
  !.gitignore
# row: 行番号(最初の行は1) len: フィールド数 fields: フィールドデータ
.gitignore以外を無視する。これで.gitignoreのみがあるので管理できる。
function callback(row, len, fields, col, field) {
 
    for ( col = 1; col <= len; col++ ) {
====== 指定ファイルのみ除外 ======
        field = fields[col]
*
        gsub(/\\/, "&&", field)  # \ は \\ にエスケープする
!.gitignore
        gsub(/\n/, "\\n", field) # 改行は \n にエスケープする
ディレクトリーを残す以外 (.gitignore1ファイル以外) に、サンプルファイルなど複数ファイルを残したい場合は、上記のように*で最初に全部除外して指定ファイルのみ含める。/は必要に応じてつける。
        print row ":" col " " field
 
    }
===== gitattributes =====
}
[https://git-scm.com/docs/gitattributes Git - gitattributes Documentation]
 
gitignoreに似ていて、パターンにマッチしたパスに対する設定を行える。
 
* text
* eol
* working-tree-encoding
* ident
* filter
* diff
* merge
* conflict-marker-size
* whitespace
* export-ignore: git archiveなどに含めないことをマーク。
* export-subst
* delta
* encoding


===== ファイルのインデックスのみ削除 =====
BEGIN { row = max_idx = 0 }
git rmは単独だと、gitの履歴とローカルファイルからも削除する。追跡対象から削除のみで、ローカルファイルとして残したい場合、--cachedを指定する。
{
git rm --cached
    idx = 0
 
    sub(/\r$/, "")
==== gitk ====
    while ($0 != "") {
 
        if (match($0, /^(["]([^"]|["]["])*["]|[^,"]*)(,|$)/)) {
===== problem =====
            fields[++idx] = ""
ブランチ名が長いと、右クリックしにくい
        } else if (match($0, /^["]/)) {
 
            fields[++idx] = substr($0, 2)
==== submodule ====
            for (;;) {
https://git-scm.com/docs/git-submodule
                if (getline == 0) exit 1
 
                sub(/\r$/, "")
https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E3%82%B5%E3%83%96%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB
                if (match($0, /^([^"]|["]["])*["](,|$)/)) break
 
                gsub(/["]["]/, "\"")
===== foreach =====
                fields[idx] = fields[idx] "\n" $0
サブモジュールの全部を一括処理する。
            }
foreach [--recursive] <command>
            fields[idx] = fields[idx] "\n"
<command>部分では$sm_pathでパスを参照できる。
        } else {
git submodule foreach 'echo $sm_path `git rev-parse HEAD`'
            exit 1
 
        }
Entering 'XXX'
        field = substr($0, RSTART, RLENGTH)
XXX hash
        $0 = substr($0, RSTART + RLENGTH)
submoduleの中に入ってから実行することに注意する。
        lastcomma = sub(/,$/, "", field) > 0
 
        gsub(/^["]|["]$/, "", field) && gsub(/["]["]/, "\"", field)
便利なコマンド。
        fields[idx] = fields[idx] field
git submodule foreach 'git reset --hard'
    }
 
    if (lastcomma) fields[++idx] = ""
==== Other ====
    while (idx < max_idx) delete fields[max_idx--]
 
    callback(++row, idx, fields)
===== 他のブランチとの同一化 =====
    max_idx = idx
git diff HEAD master | patch -p 1
}
patchの他にgit applyでもいい。
 
===== .netrc =====
https://social.senooken.jp/conversation/1573147#notice-2217499
 
Gitのパスワード入力の省略方法に~/.netrcがある。
 
しかし、man netrcするとわかるけど、これはもともとFTPのためのもの。なぜGitで使えるんだ?Gitの文書で言及がない。


In conversation Thursday, 21-Feb-2019 10:58:47 JST from web permalink
</syntaxhighlight>awkのCSVパーサー。先頭のBOMはあると認識できないので、tail -c +4でBOMを除外して使う。
tail -c +4 data/101543.csv | awk -f csvparser.awk


せのお (妹尾 賢)せのお (妹尾 賢) in reply to
=== Other ===


理由が分かった。
==== binary ====
[https://qiita.com/ko1nksm/items/dc8f247cdc5b7b58b736 POSIX準拠のシェルスクリプトでバイナリデータを扱う #Bash - Qiita]


1. Gitはhttpとhttpsの通信にcURLを使っている。
バイナリーデータの読込はodコマンド。なければhexdump。


<nowiki>https://github.com/git/git/blob/master/INSTALL#L141</nowiki>
書込はprintf。


2. cURLが.netrcにも対応しているから。
head/tailの-cはPOSIXで使えたか?


<nowiki>https://ec.haxx.se/usingcurl-netrc.html</nowiki>
==== root ====


=== GitHub ===
===== リダイレクト出力 =====
[https://blog.shaba.dev/posts/redirect-with-sudo sudo権限でリダイレクト処理を行ってファイルに書き込む方法]


==== Account ====
リダイレクトはログインユーザーの権限でなされるらしく、root権限のある場所にファイル出力できない。
Username may only contain alphanumeric characters or single hyphens, and cannot begin or end with a hyphen.
ユーザー名は、英数字と-のみが使用可能。


組織別にアカウントを分けるなら、かぶらないように末尾に-組織名のようなサフィックスがあるとよいだろう。
teeコマンドでやる。
 
pwd | sudo tee out.dat
=== Fossil ===
teeコマンド実行する側でsudoが必要。
* [https://gigazine.net/news/20231231-why-sqlite-does-not-use-git/ SQLiteがバージョン管理システムとしてGitを採用しない理由 - GIGAZINE]
* [https://gigazine.net/news/20201229-fossil/ GitとGitHubの機能をひとつのバイナリに詰め込んだ「Fossil」レビュー - GIGAZINE]


外部依存を排除しており、CGIでも動作するという点が非常に良い。気になる。Phorgeの検討が不要になる。
==== ログインシェルの確認 ====
[https://docs.oracle.com/cd/E19683-01/816-3946/customize-89075/index.html 第 10 章 動作環境のカスタマイズ (Solaris ユーザ]
ログインシェルはGUIログインでも内部的にある。ログインシェルが読みこむprofileファイルなどは、ログイン時に、1回だけ実行したい処理の記述場所として最適。
SHELL環境変数にログインシェルのパスが入っている。
echo $SHELL
/bin/bash
==== OSの判別 ====
OSTYPE環境変数に値があるのでこれで判別する。
例えば以下の値が入っている。
linux-gnu
darwin23
これらを検知して判定する。
case $OSTYPE in
  linux*) echo 'linux';;
  darwin*) echo 'Mac';;
esac
==== Configure ====
===== profile =====
[https://blog1.mammb.com/entry/2019/12/01/090000 bash の初期化ファイル .profile, .bashrc, .bash_profile の使い分けと管理方針 - A Memorandum]
環境変数など~/.profileに全部のシェルの共通設定を記述して、~/.bash_profileなどのログインシェルやbashrcなどで参照するのがいい。


[https://fossil-scm.org/home/doc/trunk/www/index.wiki Fossil: A Coherent Software Configuration Management System]
== cmd.exe ==


いくつか癖があるので注意する。
=== Control block ===


https://chatgpt.com/c/674e38de-a8c0-800b-8991-e0d68a2f0d86
==== for ====
あくまでコマンド。


複数のリポジトリーを取り扱うことは可能。ただし、Web UI上からリポジトリーの新規作成はできない。リポジトリーの新規作成はあくまでコマンドラインから行う必要がある。ここは集中的。
===== nest =====


[https://okamerin.com/nc/title/508.htm git と fossil の比較 git vs fossil-scm | タイトル]
* [https://chicagopile1-75.hatenablog.com/entry/2018/05/23/143502 バッチファイルで2重ループ - ハムスターに飼われる院生のブログ]


完全に個人なら悪くないが、コマンドの操作体系も異なるし、ややリスクがある。Tracのほうが無難。
* [https://web.archive.org/web/20230602041631/https://jj-blues.com/cms/wantto-useloop/ web.archive.org/web/20230602041631/https://jj-blues.com/cms/wantto-useloop/]


==== Install ====
ネストはできない。二重ループしたければ、関数にしてそれを呼び出す。


===== Binary =====
=== bitsadmin ===
[https://fossil-scm.org/home/doc/trunk/www/index.wiki Fossil: A Coherent Software Configuration Management System]
Windowsでのファイルダウンロードコマンド


ソースコードからコンパイルするか、コンパイル済みバイナリーを配置するだけ。
Windows 7以降ではbitsadminコマンドがあり、これがwget相当となる。
VER=2.25
mkdir -p ~/.local/stow/fossil-$VER ~/.local/bin
cd ~/.local/stow/fossil-$VER
curl -O [https://fossil-scm.org/home/uv/fossil-linux-x64-2.25.tar.gz https://fossil-scm.org/home/uv/fossil-linux-x64-$VER.tar.gz]
tar -xf fossil-$VER.*
ln -fns ../stow/fossil-$VER/fossil


===== Server =====
書式:
[https://fossil-scm.org/home/doc/tip/www/server/any/cgi.md Fossil: Serving via CGI]
bitsadmin /transfer <job name> <URL> <output path>
<job name>と<output path>は必須なので注意する。


CGIで実行するにはいくつか手順がある。
=== certutil ===
Windowsでのハッシュの確認に使える。
certutil -hashfile file


CGIディレクトリーに以下の内容のCGIスクリプトを用意する。
SHA1 ハッシュ (対象 C:\moconavi\windows\Moconavi\ext\chromium\moconavium.exe):
  #!/usr/bin/fossil
  e0da85b04b6970ac1f0c33db7a9ad607fdbd44eb
  repository: /home/fossil/repo.fossil
  CertUtil: -hashfile コマンドは正常に完了しました。
repositoryの部分は指定方法がいろいろある。単一リポジトリーのホストなら上記でいいが、複数のリポジトリーを取り扱いたければ、リポジトリー群の格納ディレクトリーをdirectory: で指定する。


また、リポジトリーが不在の場合のリダイレクト先を指定するnotfound:もある。
=== rlogin.cmd ===
  #!/usr/bin/fossil
コマンドキーの送信を自動化できる?
  directory: /home/fossil/repos
  rem rlogin.cmd
  notfound: <nowiki>http://url-to-go-to-if-repo-not-found/</nowiki>
   
CGIスクリプトをcgi-bin/repoとした場合、展開後は [http: //mydomain.org/cgi-bin/repo/XYZ] のようなURLで [/home/fossil/repos/XYZ.fossil] にアクセス可能。
  @Echo off
 
Set SERVER=192.168.0.0
CGIで展開されると。
Set USERNAME=
 
Set PASSWORD=
fossil.cgiにする。
 
Cmdkey /generic:TERMSRV/%SERVER% /user:%USERNAME% /pass:%PASSWORD%
https://chatgpt.com/c/674e38de-a8c0-800b-8991-e0d68a2f0d86
Start mstsc /v:%SERVER%
 
Timeout 5
fossilのweb uiではリポジトリーの新規作成ができない。新規作成だけはコマンドラインから行う必要がある。これだけがいまいち。保留。
Cmdkey /delete:TERMSRV/%SERVER%
=== Phorge ===
[https://we.phorge.it/ Home]


PhorgeはPhabricatorのフォーク。
=== 実行中プロセスのパスの確認 ===
出典: [https://superuser.com/questions/768984/show-exe-file-path-of-running-processes-on-the-command-line-in-windows Show EXE file path of running processes on the command-line in Windows - Super User]。
wmic process get ProcessID,ExecutablePath
wmic process where "name='mysqld.exe'" get ProcessID, ExecutablePath
wmic process where "name='mysqld.exe'" get ProcessID, ExecutablePath /FORMAT:LIST


==== About ====
=== 簡易編集モード/挿入モード ===


===== Introduction =====
* [https://softantenna.com/blog/windows-10-command-prompt-no-stop/ 【Tips】Windows 10のコマンドプロンプトが意図せず止まってしまう問題を回避する方法 | ソフトアンテナ]
[https://we.phorge.it/book/phorge/article/introduction/ ◉ Introduction]
* [https://superuser.com/questions/419717/windows-command-prompt-freezing-randomly Windows command prompt freezing randomly - Super User]


以下が主な機能。
Windows 10のcmd.exeは [簡易編集モード] が有効になっており、コマンドプロンプトを左クリックすると、テキストの選択が始まる。テキスト選択中はコマンドの実行が止まる。長時間かかるコマンドの実行中に誤操作で止まると困るので、これは無効にしたほうがよい。


* コードレビューツール=Differential
cmd.exeを起動-左上のアイコンをクリック-[規定値]/[プロパティ]-[オプション]-[□簡易編集モード] を選ぶ。
* リポジトリーブラウザー=Diffusion
* バグトラッカー=Maniphest
* ウィキ=Phiriction


GitHubの自己ホスト。
そのほか、 <code>git log</code> のような制御が移るコマンドを実行してしばらくすると、操作できなくなる。


===== Phabricator =====
[□挿入モード] にすると回避できる模様。
[[wikipedia:Phabricator|Phabricator - Wikipedia]]


PhabricatorはもともとFacebook社内のBTSシステム。PHP製。2021-06-01に開発終了。
== Web ==


主なユーザー。
=== URL ===


* AngularJS
==== クエリー配列 ====
* Discord
* Facebook


==== Install ====
* [https://shinkufencer.hateblo.jp/entry/2019/05/18/163912 クエリストリングで配列を表現をするケースをざっと調べる - コード日進月歩]
* [https://qiita.com/s4kd0R/items/8a11d88099008bb1e9dc PHPでクエリパラメータから配列を受け取る物語 #JavaScript - Qiita]
* [https://www.php.net/http_build_query PHP: http_build_query - Manual]


* [https://we.phorge.it/book/phorge/article/installation_guide/ ◉ Installation Guide]
やり方がいくつかある。
* [https://ipv6.rs/tutorial/Ubuntu_Server_Latest/Phorge/ Self Host with IPv6rs - IPv6 Provider - How to Install Phorge on Ubuntu Server Latest]
* https://chatgpt.com/c/6749041b-a1b4-800b-a134-96a8029c086e


===== Requirement =====
# CSV文字列で受取後分割: <nowiki>https://www.sakdor.net/test/?var=1,2,3</nowiki> explode(",",$_GET[var]);
LAMP環境で動作する。
# 配列添字
 
## http://www.sakdor.net/test/?var&#x5B;&#x5D;=1&var&#x5B;&#x5D;=2&var&#x5B;&#x5D;=3
共用ホストでも動作するが、一部機能しない。通常コンピューターを推奨している。
## http://www.sakdor.net/test/?var&#x5B;a&#x5D;=1&var&#x5B;b&#x5D;=2&var&#x5B;c&#x5D;=3
 
## http:www.sakdor.net?var[0]=1&var[1]=2&var[2]=3
* MySQL: 5.5以上。
* PHP 7.2以上
* git: 2.5.0以上。
* PHP extension: mbstring, iconv, mysql (or mysqli), curl, pcntl


ドメインはサブディレクトリーはだめで、サブドメインじゃないとダメ。
データが決まっているならcsvがシンプル。


===== Download =====
==== CGI ====
以下のコマンドで取得する。
https://chatgpt.com/c/67634332-a3b8-800b-87a2-e21bd21a1cfc
$ cd somewhere/ # pick some install directory
somewhere/ $ git clone <nowiki>https://we.phorge.it/source/arcanist.git</nowiki>
somewhere/ $ git clone <nowiki>https://we.phorge.it/source/phorge.git</nowiki>
gitの設定。
$ sudo git config --system --add safe.directory somewhere/arcanist
$ sudo git config --system --add safe.directory somewhere/phorge
phorge用のDBを作っておく。
cp /var/www/html/phorge/phabricator/conf/local/local.json.example /var/www/html/phorge/phabricator/conf/local/local.json


"mysql.host": "localhost", "mysql.user": "phorge", "mysql.pass": "password", "mysql.port": 3306, "mysql.charset": "utf8", "mysql.database": "phorgedb"
WordPressなどのWebアプリだとファイル拡張子が登場しない。これはいくつかの仕組みが組み合わさって実現されている。
後は開くだけ。


実操作。
# '''パーマリンク設定''' によるクリーンなURL構造の生成。
# '''.htaccess(Apache)''' や '''リライトルール''' によるURLの書き換えとルーティング。
# '''index.php''' を起点とする動的な処理。
# '''テンプレート階層''' に従って適切なPHPファイルを呼び出す。


こういうディレクトリー構成想定。
.htaccessでindex.phpにリダイレクトして、index.phpから全て処理している。これにより省略できている。
public_html
+ phorge.gnusocial.jp 公開ディレクトリー。
+ phorge phorge関係の格納場所。
  + phorge
  + arcanist
取得。
TAG=2024.35
mkdir phorge
cd phorge
PKG=phorge
git clone --depth 1 [https://we.phorge.it/source/phorge.git https://we.phorge.it/source/$PKG.git]
cd $PKG; git fetch --depth 1 origin tag $TAG; git checkout $TAG; cd ..
PKG=arcanist
git clone --depth 1 [https://we.phorge.it/source/arcanist.git https://we.phorge.it/source/$PKG.git]
cd $PKG; git fetch --depth 1 origin tag $TAG; git checkout $TAG; cd ..


git config --add safe.directory arcanist
同じ用に、アプリ側が対応していれば、index.fcgiに全部リダイレクトして、パスを解釈してくれるなら、/でのアクセスもできる気がする。
git config --add safe.directory phorge
phorge/webrootが公開ディレクトリーになるので、これをシンボリックリンクで公開ディレクトリーにリンクする。
DOMAIN=phorge.gnusocial.jp
ln -fns phorge/phorge/webroot ../$DOMAIN
「[https://we.phorge.it/book/phorge/article/configuration_guide/ ◉ Configuration Guide]」に記載のあるリダイレクト設定をする。


以下相当の設定を行う。
[https://stackoverflow.com/questions/36405496/how-can-i-run-a-fastcgi-script-in-root-url-without-path apache - How can I run a FastCGI script in root url (/ - without path)? - Stack Overflow]
<VirtualHost *>
  # Change this to the domain which points to your host.
  ServerName phorge.example.com
  # Change this to the path where you put 'phorge' when you checked it
  # out from the upstream when following the Installation Guide.
  #
  # Make sure you include "/webroot" at the end!
  DocumentRoot /path/to/phorge/webroot
  RewriteEngine on
  RewriteRule ^(.*)$          /index.php?__path__=$1  [B,L,QSA]
</VirtualHost>
<Directory "/path/to/phorge/webroot">
  Require all granted
</Directory>
具体的には、phorge/webroot/.htaccessに以下を記載して、ファイルがなければ作成する。
cat >phorge/webroot/.htaccess <<-'EOT'
RewriteEngine on
RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA]
EOT
上記設定後phorge.gnusocial.jpにアクセスすると以下のエラーになる。
Request parameter '__path__' is not set. Your rewrite rules are not configured correctly.


* [https://stackoverflow.com/questions/25368612/phabricator-rewrite-rules-configuring-issue apache - Phabricator rewrite rules configuring issue - Stack Overflow]
=== HTTP ===
* [https://stackoverflow.com/questions/49344737/phabricator-install-rewrite-rules-are-not-configured-correctly php - Phabricator install. Rewrite rules are not configured correctly - Stack Overflow]
[https://www.rfc-editor.org/rfc/rfc9110.html RFC 9110: HTTP Semantics]


上記が少し参考になる。require指令を指定していないのが問題。
==== Content-Disposition ====
[https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Content-Disposition Content-Disposition - HTTP | MDN]


うーん。この問題を解決できない。調べても解決例が出てこない。断念する。他のソフトにする。
[https://datatracker.ietf.org/doc/html/rfc6266 RFC 6266 - Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)]
Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"
filenameでファイル名を指定する。ここの値は二重引用符で囲む。スペースを含む場合に必須になる。


===== Config =====
==== multipart/form-data ====
[https://we.phorge.it/book/phorge/article/configuration_guide/ ◉ Configuration Guide]
rfc7578


以下のコマンドでユーザーを認識させる。
* [https://datatracker.ietf.org/doc/html/rfc7578 RFC 7578 - Returning Values from Forms: multipart/form-data]
phorge/ $ ./bin/storage upgrade --user <user> --password <password>
* [https://qiita.com/sivertigo/items/14957200af5ad953d63b Multipart/form-dataの仕様メモ #HTTP - Qiita]


==== Diffusion ====
ファイルアップロード用のMIME type。


===== Hosting =====
リクエストヘッダー
[https://we.phorge.it/book/phorge/article/diffusion_hosting/ ◉ Diffusion User Guide: Repository Hosting]
Content-Type: multipart/form-data; boundary=--hogehoge
 
リクエストボディー
=== Kallithea ===
--hogehoge
[https://kallithea-scm.org/ Kallithea]
Content-Disposition: form-data; name="user_name"
 
Content-Type: text/plain
https://chatgpt.com/c/674f8938-8590-800b-9a4c-f1ec04fc5869
 
test
Python 3.6でCGIでも動作する管理ソフト。
--hogehoge
 
Content-Disposition: form-data; name="email"
[https://kallithea.readthedocs.io/en/stable/index.html Kallithea Documentation — Kallithea 0.7.0 documentation]
sample@mail.com
--hogehoge
Content-Disposition: form-data; name="gender"
male
--hogehoge
Content-Disposition: form-data; name="user_profile" filename="image.jpeg"
Content-Type: image/jpeg
\xff\xd8\....
--hogehoge--
ヘッダーでmultipart/form-dataを明記して、ボディーでデータを指定する。


紹介: [https://www.farend.co.jp/blog/2015/08/kallithea/ GitとMercurialに対応のリポジトリ管理ツール「Kallithea」 - ファーエンドテクノロジー株式会社]
[https://weblabo.oscasierra.net/curl-post/ curlコマンドでPOSTする, 様々な形式別メモ |]


==== Administrator guide ====
curlでの送信理由。


===== Installation on Unix/Linux =====
-Fで送信データをname=data形式で指定する。ファイルの内容を指定する場合、@filenameで指定する。これを指定すると、リクエストボディーのfilename扱いにしてくれる模様。-Fを指定すると、-H 'Content-Type: multipart/form-data'が自動付与される。たぶん、-dと同様に-X POSTもつく。
[https://kallithea.readthedocs.io/en/stable/installation.html Installation on Unix/Linux — Kallithea 0.7.0 documentation]
curl -X POST -F file1=@/var/tmp/sample.jpg <nowiki>https://xxxxx.net/xxxxxx</nowiki>
データとテキストを同時送信したい場合、-Fで複数指定する。
curl -X POST -F 'age=30' -F file1=@/var/tmp/sample.jpg <nowiki>https://xxxxx.net/xxxxxx</nowiki>
curlだと上記のboundaryなどをうまくやってくれるのだと思う。


====== ディレクトリー構造 ======
リクエストボディー全体をファイルデータにする場合。
https://chatgpt.com/c/674f8938-8590-800b-9a4c-f1ec04fc5869
curl -X POST -H 'Content-Type: image/jpeg' --data-binary @/var/tmp/sample.jpg <nowiki>https://xxxxx.net/xxxxxx</nowiki>
/var/www/kallithea/
├── config/                  # 設定ファイルやシークレットを保存
│  └── kallithea.ini        # Kallitheaのメイン設定ファイル
├── data/                   # データベースや一時ファイル用ディレクトリ
│  ├── db.sqlite            # SQLiteの場合のデータベースファイル
│  └── sessions/            # ユーザーセッションデータ
├── logs/                   # ログファイル保存ディレクトリ
│  └── kallithea.log        # メインのアプリケーションログ
├── repos/                  # Git/Mercurialリポジトリを保存するディレクトリ
│  ├── project1.git/        # プロジェクト1のGitリポジトリ
│  └── project2.hg/        # プロジェクト2のMercurialリポジトリ
├── static/                  # 静的ファイル(JavaScript, CSS, 画像など)
│  ├── css/
│  ├── js/
│  └── img/
└── venv/                    # Python仮想環境
    ├── bin/
    ├── lib/
    └── ...
static配下が公開ディレクトリー。共用サーバーの場合。public_htmlにkallitheaとkallithea.domainでシンボリックリンクでやるとよさそう。


====== Installing a released version in a virtualenv ======
=== IP address ===
いくつか方法があるが、virtualenvが推奨されている。
出典: [https://glocalnet.jp/vpn/topix/archives/67#:~:text=%EF%BC%94%EF%BC%8E%E5%9B%BA%E5%AE%9AIP%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%AE%E5%8F%96%E5%BE%97%E6%96%B9%E6%B3%95%20%E5%8F%96%E5%BE%97%E6%96%B9%E6%B3%95%E3%81%AF%E4%B8%BB%E3%81%AB3%E3%81%A4%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82,%E3%83%BB%E5%A5%91%E7%B4%84%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E3%83%97%E3%83%AD%E3%83%90%E3%82%A4%E3%83%80%E3%81%A7%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A8%E3%81%97%E3%81%A6%E7%94%B3%E3%81%97%E8%BE%BC%E3%82%80%E6%96%B9%E6%B3%95%20%E3%83%BB%E5%9B%BA%E5%AE%9AIP%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%AB%E5%AF%BE%E5%BF%9C%E3%81%97%E3%81%A6%E3%81%84%E3%82%8BSIM%E3%82%92%E5%A5%91%E7%B4%84%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%20%E3%83%BBVPN%E3%82%92%E5%88%A9%E7%94%A8%E3%81%97%E3%81%9F%E5%9B%BA%E5%AE%9AIP%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%AE%E6%8F%90%E4%BE%9B%E4%BC%9A%E7%A4%BE%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95 固定IPアドレスの取得方法 ~実は簡単!フリーランスの方も必見です~|VPN活用日記|トピックス|グローカルネットの快適VPN【公式】| 株式会社グローカルネット]。


coreserver v1のpythonはpython 3.6だった。
自宅サーバーを行う際、固定IPアドレスが必要になる。
cd public_html/
DOMAIN=kallithea.gnusocial.jp
cd $DOMAIN
python3 -m venv venv
python3 -m venv venvの実行時に以下のエラー。
Error: Command '['/virtual/senooken/public_html/kallithea.gnusocial.jp/venv/bin/python3', '-Im', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit status 2.
[https://qiita.com/sin9270/items/7a17d21ccd7c2531ac41 cimg/pythonでvenvによる仮想環境の作成がエラーになる #Python - Qiita]


pipが見つからないのが原因の模様。--without-pipでインストールして、仮想環境内にpipを直接インストールする。
取得方法がいくつかある。
python3 -m venv --without-pip venv
. venv/bin/activate
curl https://bootstrap.pypa.io/pip/<nowiki>$(python3 -V | grep -o '[0-9].[0-9]')/get-pip.py -o get-pip.py</nowiki>
python3 get-pip.py
pip install --upgrade pip
OK。以下のコマンドで基本要件を確実にする。
pip install --upgrade pip "setuptools<67"
Kallitheaをインストール。
pip install --upgrade kallithea
なんかエラーが出る。
  ERROR: Command errored out with exit status 1:
    command: /virtual/senooken/public_html/kallithea.gnusocial.jp/venv/bin/python3 -c 'import io, os, sys, setuptools, tokenize; sys.argv[0] = '"'"'/export/tmp/pip-install-4k2ozlqh/formencode_9f25a10925bf49da975ba94c0fbba946/setup.py'"'"'; __file__='"'"'/export/tmp/pip-install-4k2ozlqh/formencode_9f25a10925bf49da975ba94c0fbba946/setup.py'"'"';f = getattr(tokenize, '"'"'open'"'"', open)(__file__) if os.path.exists(__file__) else io.StringIO('"'"'from setuptools import setup; setup()'"'"');code = f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /export/tmp/pip-pip-egg-info-kjtbdngw
        cwd: /export/tmp/pip-install-4k2ozlqh/formencode_9f25a10925bf49da975ba94c0fbba946/
  Complete output (3 lines):
  /usr/lib64/python3.6/distutils/dist.py:261: UserWarning: Unknown distribution option: 'convert_2to3_doctests'
    warnings.warn(msg)
  error in FormEncode setup command: use_2to3 is invalid.
  ----------------------------------------
WARNING: Discarding <nowiki>https://files.pythonhosted.org/packages/2f/53/707c2b9b65ea6bedde67c21cbf7c71394f4a198620d4e9c1771214b91dcc/FormEncode-1.3.1.tar.gz#sha256=ada2f51792b1b484e5bb7b6cc14acfc1bc11fafc967cf015cd57e856053ca7f6</nowiki> (from <nowiki>https://pypi.org/simple/formencode/</nowiki>). Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
Collecting kallithea
[error in FormEncode setup command: use_2to3 is invalid.]


[https://qiita.com/nkmr_RL/items/85edc2ee68c01ec5582e 急にpip installで一部のライブラリのインストールが失敗するようになった件 #Python3 - Qiita]
* 契約しているプロバイダでオプションとして申し込む方法
* 固定IPアドレスに対応しているSIMを契約する方法
* '''VPNを利用した固定IPアドレスの提供会社を利用する方法'''


setuptoolsを58.0.0未満にすればいいらしい。
VPNの固定IPアドレスが安いらしい。ryoかsuwakoが解説していた気がする。
pip install setuptools==57.4.0
この実行後pip install --upgrade kallitheaが成功。


====== Prepare front-end files ======
=== Authentication ===
以下のコマンドでフロントエンドを用意。
認証方式がいくつかある。HTTPで定義される認証方式 (HTTP認証) が有名。
kallithea-cli front-end-build
事前にnpmが必要な模様。
FileNotFoundError: [Errno 2] No such file or directory: 'npm': 'npm'
npmをインストールしたら解決。


===== Setup =====
==== Basic認証 ====
[https://kallithea.readthedocs.io/en/stable/setup.html Setup — Kallithea 0.7.0 documentation]
出典: [https://ja.wikipedia.org/wiki/Basic%E8%AA%8D%E8%A8%BC Basic認証 - Wikipedia]


====== Setting up a Kallithea instance ======
Authorization HTTPヘッダーにBasicのあとに [username:password] をBASE64でエンコードして送信する認証方式。
まず以下のコマンドでmy.iniを作成する。
GET /private/index.html HTTP/1.1
  kallithea-cli config-create my.ini http_server=waitress
  Host: example.com
http_serverのところで使用するHTTPサーバー種別を指定する。waitress, gearbox, gevent, gunicorn, or uwsgi.を指定可能。
Authorization: Basic cm9vdDpwYXNzd29yZA{{=}}{{=}}
盗聴や改ざんが簡単だが、シンプルという利点がある。


ひとまずデフォルトのこれで。
[https://dev.classmethod.jp/articles/delete-cache-for-basic-authentication/ Basic認証のキャッシュを削除する(ログアウトする) | DevelopersIO]


続いてDBを作成する。PostgreSQL/SQLIte/MariaDB/MySQLに対応。最初はSQLiteを使用しておいて、後で他のDBへのアクセスが推奨されている。
ログアウト時は、hoge@domainのようにパスワードを省略した任意のユーザー名でログインを試みて既存のログイン状況を上書きする模様。


が、共用サーバーだと書き込みでプロセス削除されると嫌なので最初からMariaDBにする。まず以下のコマンドでドライバーを取得。
Digest認証も共通。
  pip install mysqlclient


  OSError: mysql_config not found
==== Digest認証 ====
mariadbは違う模様。以下の開発パッケージが必要らしい。
[https://qiita.com/Threen/items/409971705767e2f89fb2 Basic認証・Digest認証・Form認証をざっくり理解 #Security - Qiita]
  sudo apt-get install libmysqlclient-dev
不明。一旦スキップ。


SQLite以外を使う場合、my.iniでsqlalchemy.urlのコメントアウトを解除してDBのユーザー名とパスワードを記入しておく。
HTTP標準の認証。Basic認証とほぼ同じ。ただし、パスワードをハッシュ化している。そのため、DBのパスワードが流出した場合に比較的安全。
#########################
##      DB CONFIG      ##
#########################
#sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
#sqlalchemy.url = postgresql://kallithea:password@localhost/kallithea
#sqlalchemy.url = mysql://kallithea:password@localhost/kallithea?charset=utf8mb4
sqlalchemy.url = mysql://[username]:[password]@localhost/kallithea?charset=utf8mb4
## Note: the mysql:// prefix should also be used for MariaDB
用意したら以下のコマンドで初期テーブルを作成する。
kallithea-cli db-create -c my.ini --reuse
--reuseを指定しないと、DBやアカウントを作るところからやる。


my.ini内の情報はオプションでも指定できる。
==== OAuth ====
kallithea-cli db-create -c my.ini --user=nn --password=secret --email=nn@example.com --repos=/srv/repos
Ref
以下のエラー。
ModuleNotFoundError: No module named 'MySQLdb'
mariadb_configをコピーするとか。共用サーバーだとこの問題の対応が難しいかもしれない。PostgreSQLでやり直す。


postgresqlを使うようにmy.iniを直して実行すると以下のエラー。
* [https://ja.wikipedia.org/wiki/OAuth OAuth - Wikipedia]
ModuleNotFoundError: No module named 'psycopg2'
インストールしてみる。
pip install psycopg2
動作した?以下の質問がきた。
Are you sure to destroy old database? [y/n]y


sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) FATAL:  password authentication failed for user "senooken_kallithea"
OAuth (オーオース) 権限の認可のための標準。OAuth 2.0が最新の標準。
p


パスワードを間違えた?yだと全削除になるからかな。nなら何も出なかった。
以下が登場人物。


my.iniの指定がまずかった。
* resource owner: あるサイトのユーザー。
#sqlalchemy.url = postgresql://kallithea:password@localhost/kallithea
* resource server: あるサイトのユーザーのデータの保有サーバー。
sqlalchemy.url = postgresql://senooken_kallithea:WkiXF3w7d@localhost/senooken_kallithea
* clent: クライアントアプリ。リソースサーバーのデータを使用したい。
DBの指定も必要。
* authorization server: クライアントにサイトへのアクセスを認証するサーバー。アクセストークンを発行して行う。


実行ログを見るといかが出ている。
アクセストークンが実質的なパスワードのようなものだが、resource serverのパスワードを直接渡していない点が重要な違い。パスワードを直接渡さないことで、機能別に権限を細かく利用可否を制御できる。
/virtual/senooken/public_html/kallithea/venv/lib64/python3.6/site-packages/psycopg2/__init__.py:144: UserWarning: The psycopg2 wheel package will be renamed from release 2.8; in order to keep installing from binary please use "pip install psycopg2-binary" instead. For details see: <<nowiki>http://initd.org/psycopg/docs/install.html#binary-install-from-pypi</nowiki>>.
  """)
インストールし直す。
pip install psycopg2-binary
実行し直し。
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) connection to server at "localhost" (::1), port 5432 failed: FATAL:  password authentication failed for user "senooken_kallithea"
若干内容が変わる。ポート番号が怪しい。タイムオーバー。


https://chatgpt.com/c/67547095-c29c-800b-9530-650c7ff70756
処理の流れ。


KallitheaはCGI未対応。見送ったほうがいいかも。
# client->resource owner: Authorization Request。ここでユーザーが手操作でアクセスを承認する。
# client<-resource owner: Authorization Grant。
# client->authorization server: Authorization Grant。承認された情報でアクセストークンを要求。
# client<-authorization server: Access Token
# client->resource server: Access Token。アクセストークンでアクセス。
# client<-resource server: Access Token


=== Trac ===
Consumer Key/Secret: アプリ識別用のID/PW。
https://chatgpt.com/c/67546eda-20ac-800b-b37f-7e8954c128f5


[https://trac.edgewall.org/ The Trac Project]
Access Token: サイトにアクセスするためのパスワード。


CGIで動作するリポジトリー統合のあるBTS。
=== API ===


==== Install ====
==== 複数レコードの登録 ====
[https://trac.edgewall.org/wiki/TracInstall TracInstall – The Trac Project]
[https://buddypia.com/2021/11/14/%E8%A4%87%E6%95%B0%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89api%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%AA%BF%E3%81%B9%E3%81%A6%E3%81%BF%E3%81%9F%E8%A9%B1/ 複数レコードの登録・更新・削除のREST APIについて調べてみた話(+@ Graph API) - junode | 個人開発ブログ]


[https://trac.edgewall.org/wiki/TracFastCgi TracFastCgi – The Trac Project]
既存のAPIは単一リソースの処理しかないことが多い。JavaScriptなどで単一リソースを何回も呼べばいいというのはそうだけど、JavaScriptなしでは動作しない。一括処理用のAPIを作るしかなくないか?


[https://trac.edgewall.org/browser/tags/trac-1.6/INSTALL.rst tags/trac-1.6 の INSTALL.rst – The Trac Project]
[https://www.yamarkz.com/blog/rest-web-api-practice REST WebAPIのプラクティス | yamarkz.com]


[https://zenn.dev/matobaa/articles/trac_16_on_docker Trac 1.6 を Docker で建てる]
delete_bulkなどのような一括処理用のAPIを作るしかない。内部的には単一処理のAPIを作る感じだったとしても。


[https://chatgpt.com/c/675504b7-29c0-800b-bb09-5e8a24709488 http s://chatgpt.com/c/675504b7-29c0-800b-bb09-5e8a24709488]
==== パラメーター ====
[https://stackoverflow.com/questions/25385559/rest-api-best-practices-args-in-query-string-vs-in-request-body json - REST API Best practices: args in query string vs in request body - Stack Overflow]


* [https://kiban.dbcls.jp/togordf/wiki/TracFastCgi TracFastCgi – TogoRDF]
パラメーターの指定に3種類ある。
* [https://kiban.dbcls.jp/togordf/wiki/TracCgi TracCgi – TogoRDF]
* [https://qh73xebitbucketorg.readthedocs.io/ja/latest/1.Programmings/python/LIB/trac/install/ 1. 導入方法 — 苦労する遊び人の玩具箱 1 ドキュメント]
* [https://blog.masasuzu.net/entry/20101003/1285909461 virtualenv上でtrac-gitを動かして見る。 - 目の前に僕らの道がある]


「[https://trac.edgewall.org/browser/tags/trac-1.6/INSTALL.rst tags/trac-1.6 の INSTALL.rst – The Trac Project]」を参考に取り組む。
# リクエストボディー
# クエリー
# パス


===== Installing Trac =====
パスはIDなどを指定する場合だけわかりやすい。それ以外のオプションはクエリーのほうがいい。
以下のディレクトリー構成を踏襲する。
/var/www/kallithea/
├── config/                  # 設定ファイルやシークレットを保存
│  └── kallithea.ini        # Kallitheaのメイン設定ファイル
├── data/                    # データベースや一時ファイル用ディレクトリ
│  ├── db.sqlite            # SQLiteの場合のデータベースファイル
│  └── sessions/            # ユーザーセッションデータ
├── logs/                    # ログファイル保存ディレクトリ
│  └── kallithea.log        # メインのアプリケーションログ
├── repos/                  # Git/Mercurialリポジトリを保存するディレクトリ
│  ├── project1.git/        # プロジェクト1のGitリポジトリ
│  └── project2.hg/        # プロジェクト2のMercurialリポジトリ
├── static/                  # 静的ファイル(JavaScript, CSS, 画像など)
│  ├── css/
│  ├── js/
│  └── img/
└── venv/                    # Python仮想環境
    ├── bin/
    ├── lib/
    └── ...
複数のtrac環境がある場合、プロジェクト名部分がURLで分かれる模様。


インストーラーやOSのパッケージマネージャーを使う方法もある。公式の推奨はpipの模様。
ボディーは、通常サーバーのアップロード・ダウンロードデータとして使われる。クエリーはデータの指定に使う。
pip3 install --user trac
レンタルサーバーのpip3を使うと以下のエラー。
PermissionError: [Errno 13] Permission denied: '/etc'
venvを挟む。
mkdir -p ~/public_html/trac
cd ~/public_html/trac
python3 -m venv --without-pip venv
. venv/bin/activate
curl <nowiki>https://bootstrap.pypa.io/pip/$(python3</nowiki> -V | grep -o '[0-9].[0-9]')/get-pip.py -o get-pip.py
python3 get-pip.py
pip install --upgrade pip
pipの環境ができたのでtracをインストールする。
pip3 install trac
trac-1.6をこれでインストールできた。


必要な依存関係をインストールする。
この原則に従うとシンプルだろう。
trac-admin [project] initenv
プロジェクトディレクトリーとプロジェクト名の命名に悩む。


Tracはプロジェクトという単位で管理する。1個のプロジェクトに関連するリポジトリーを複数まとめることは可能。fossil同様設定ファイルなどで手動で管理する。が、サードパーティープラグインでWeb UIから追加も可能とのこと。
* URIには長さの制限がある。
* ボディー
** 引数が非常に多い場合。
** 画像などバイナリーデータ。
** キー・値構造を持たない場合。
* クエリー文字列
** 引数を簡単に確認できる。
** 共通の引数の場合。


例えば、gnusocial/GNU socialというような形。
==== 検索機能のGET/POST ====


[https://trac.edgewall.org/wiki/TracAdmin#initenv TracAdmin – The Trac Project]
* [https://stackoverflow.com/questions/20550514/post-or-get-in-a-search-form .net - POST or GET in a search form? - Stack Overflow]


initenvは後ろにプロジェクト名とdbを指定できる。
検索機能にGETとPOSTのどちらを使うか?という議論がある。
trac-admin <project> initenv [<project name> <db>]
[project]/conf/trac.iniの以下に反映される。


* <project name>=project.name
データ登録するわけなじゃないのだから、GETがいいんじゃない?
* <db>=trac.database (初期値=sqlite:db/trac.db)


https://chatgpt.com/c/67561e46-db8c-800b-80e8-b3f90bab4247
POSTだと、JSONをそのまま送れるので、複雑なケースに対応できる。特に、配列の送信が重要。


mysqlを使う場合、mysql:
GETのほうが検索条件をブックマークにできたり、URLを共有できるので、基本は便利。


mysql:host=localhost;port=3306;dbname=your_database_name
ただし、検索などのパラメーターが長くなる場合、使用できない。そもそも検索でそんなに長いパラメーターというのがまずいかもしれない。2000文字あれば十分という説がある。


[https://trac.edgewall.org/wiki/TracEnvironment#DatabaseConnectionStrings TracEnvironment – The Trac Project]
==== レート制限対策 ====


DB文字列の書式
* [https://pikodon.com/note/php/api-cache/ APIの利用制限対策 | Web開発ノート]
mysql://username:password@host:port/dbname
* [https://keirinomikata.zendesk.com/hc/ja/articles/4404549985945-%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E6%95%B0%E3%81%AB%E3%82%88%E3%82%8B%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%88%B6%E9%99%90%E3%81%AE%E5%AF%BE%E7%AD%96%E6%96%B9%E6%B3%95 リクエスト数によるアクセス制限の対策方法 – 請求管理ロボ ヘルプ]


いろいろ方法がある。


[:]区切りの部分は順不同の模様。
* cronなどでデータをサーバー上 (DBなど) に定期保存して、保存データを表示させる。
trac-admin gnusocial initenv 'GNU social' 'mysql://senooken_trac:password@localhost/senooken_trac';
* 配列を利用して、1回のリクエストでまとめて取得する。
localhostは省略不能。
* インターバルを設ける。
* HTTP 429/413を検知して、リトライする。


[https://kiban.dbcls.jp/togordf/wiki/TracInstall TracInstall – TogoRDF]
==== 指数関数的バックオフ ====
tracのmysql対応が不十分の模様。


PyMySQLモジュールを使う
* [https://docs.link.getmoneytree.com/docs/faq-rate-limiting APIレート制限は何か、どのように対処するのか?]
* [[wikipedia:Exponential_backoff|Exponential backoff - Wikipedia]]
* [https://cloud.google.com/memorystore/docs/redis/exponential-backoff?hl=ja 指数バックオフ  |  Memorystore for Redis  |  Google Cloud]
* [https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/cloud-design-patterns/retry-backoff.html バックオフパターンで再試行 - AWS 規範ガイダンス]リトライ時は以下のアルゴリズムがいいらしい。
wait_interval = base * 2^n +/- jitter


[https://trac.edgewall.org/wiki/MySqlDb MySqlDb – The Trac Project]
* <code>wait_interval</code> は、API が HTTP 429 で応答した場合に、システムがリクエストを再試行するまでの時間となります。
  pip install PyMySQL
* <code>base</code> は最初の間隔、つまり最初の再試行までの待ち時間です。この値には3000msを使用することをお勧めします。
* <code>n</code> は、現在の呼び出しの前にリクエストが通らなかった数です。複数のスレッドやプロセスを使用して並行してAPIを呼び出している場合、<code>n</code>の値は現在のスレッド/プロセスにスコープされます。この値は、現在のスレッド/プロセスが、最後に成功した応答から何回 429 "Too Many Requests" エラーに遭遇したかを表します。
* <code>jitter</code> は 0 から <code>base</code> の間の乱数です。これは、複数のスレッド/プロセスが全く同時にAPIを呼び出さないように、リクエストを少しずつ分散させるために使用されます。システムが待機するたびに、この乱数値を再計算し <code>wait_interval</code> の合計に加算するか減算するか、ランダムで選択してください。


==== バックエンドとフロントエンドの分離 ====
https://chatgpt.com/c/6747e923-6174-800b-8816-dd741721de45


コマンドを実行したらいかが表示される。
SPA (Single Page Application) やJAMStackの影響で、バックエンドはデータを返すだけで、画面描画はフロントエンドが全部するというのが最近の流行。
Creating a new Trac environment at /virtual/senooken/public_html/trac/gnusocial
Project environment for 'GNU social' created.
You may configure the environment by editing the file:
  /virtual/senooken/public_html/trac/gnusocial/conf/trac.ini
You can run the Trac standalone web server `tracd` and point
your browser to <nowiki>http://localhost:8000/gnusocial</nowiki>.
  tracd --port 8000 /virtual/senooken/public_html/trac/gnusocial
Navigate to "Help/Guide" to browse the documentation for Trac,
including information on further setup (such as deploying Trac
to a real web server).
The latest documentation can also be found on the project
website:
  <nowiki>https://trac.edgewall.org/</nowiki>


SSR (Server Side Rendering) とCSR (Client Side Rendering) の違い。フロントエンドの高度化や分業などが理由とのこと。


これでコマンドでローカルサーバーを起動できるようになっている。
SSRの利点。


===== Deploying Trac =====
* SEO
* 初期表示。
* 匿名。


====== Runnning the Stadaalone Server ======
SSRの課題。
以下のコマンドでローカルサーバーで起動。
tracd --port 8000 </path/to/myproject>
このあと [http://localhost:8000<nowiki>] で開ける。tracdが把握する全環境を表示して、/myprojectで該当プロジェクトを開ける。なお、プロジェクトが1個の場合-sをつけると/myprojectのパスがトップディレクトリーになる模様。</nowiki>


===== Running Trac on a Web Server =====
* サーバー負荷: データとHTML作成を同時に行うから。
単独サーバーではなくWeb Server経由で実行することもできる。
* 分散困難:


FastCGIでの動作なら共用サーバーでも稼働可能。
キャッシュの活用がポイントになるとのこと。


====== Generating the Trac cgi-bin directory ======
=== Network ===
CGI用のスクリプトはtrac-admin deplyコマンドで生成する。
trac-admin /var/trac/<project> deploy var/www
ls /var/www


cgi-bin htdocs
==== ssh ====


chmod ugo+x /var/www/cgi-bin/*
===== ssh-addの自動登録 =====
cgi-bin/は以下がある。
ssh agentに秘密鍵の登録は以下のコマンド。
  trac.cgi  trac.fcgi  trac.wsgi
  ssh-add <秘密鍵のpath>
実手順。
ただし、上記コマンドは再起動すると登録が消えるので毎回必要。
cd ~/public_html/trac
trac-admin gnusocial deploy .


  ls
~/.ssh/configに以下の内容を記入しておくと、次回からkeychainから自動で読み込まれるらしい ([https://qiita.com/sonots/items/a6dec06f95fca4757d4a macOS で再起動しても ssh agent に秘密鍵を保持させ続ける二つの方法 #SSH - Qiita])。
cgi-bin  get-pip.py  gnusocial  htdocs  venv
  Host *
htdocsにはcommon siteがある。
  UseKeychain yes
  AddKeysToAgent yes
うまくいかなかった。


trac-admin gnusocial deploy .でhtdocs配下にプロジェクトファイル群が共通で格納される模様。このhtdocsをdocument rootの公開ディレクトリにシンボリックリンクを作成するとよさそう。
[https://aifan.jp/2022/01/25/ssh-add%E3%82%92pc%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8B%E5%BA%A6%E3%81%AB%E8%87%AA%E5%8B%95%E7%9A%84%E3%81%AB%E5%AE%9F%E8%A1%8C%E3%81%95%E3%81%9B%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E8%A8%AD%E5%AE%9A/ ssh-addをPC起動する度に自動的に実行させるための設定 | AIFAN]


====== Mapping Static Resources ======
id_rsaの場合はIdentityFileを省略できるが、それ以外は指定が必要な模様。
tracの主な2個の静的リソースのURLパスが/chrome/commonと/chrome/site。追加で/chrome/<plugin>
Host *
  UseKeychain yes
  AddKeysToAgent yes
  IdentityFile ~/.ssh/id_ed25519


deployコマンドは以下のディレクトリーを作成する。
===== ssh経由でのリダイレクト出力 =====
[https://superuser.com/questions/400714/how-to-remotely-write-to-a-file-using-ssh bash - How to remotely write to a file using SSH - Super User]


* common/: tracの静的リソース。
ssh経由で標準入力内容からファイルをリダイレクトで作成したいことがある。
* site/: htdocsのコピー。
* shared: 複数のtracで共有する静的リソース。場所は[inherit].htdocs_dirで定義。
* <plugin>/


なお、静的リソースURLパスはtrac.iniで制御している
sshのコマンド部分を文字列にすればOK。
  [trac]
ssh user@remotehost -T "cat > /remotefile.txt" <<-EOT
  htdocs_location = <nowiki>http://static.example.org/trac-common/</nowiki>
  Some text
上記設定に加えて以下のシンボリックリンク作成でchromeではなくtrac-commonを使える。
  EOT
ln -s /path/to/trac/htdocs/common /var/www/static.example.org/trac-common
-Tで擬似端末を無効にしている。
ここのパスがよくわからない。deployでtrac.gnusocial.jpを指定したほうがいいのかもしれない。
===== パスフレーズの省略 =====
* [https://zenn.dev/luvmini511/articles/65786667221313 SSH パスフレーズ 省略したい!~ config 設定するか Keychain 登録自動化するか ~]
* [https://madoverload.com/2022/04/29/mac-ssh-agent/ Macのssh-agent]
SSH多段接続時とgit cloneでSSH鍵参照時に、パスフレーズを要求される。毎回要求されるのが手間。これを省略する方法がある。
~/.ssh/configに以下の設定を記述する。
Host *
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/id_ed25519
* AddKeysToAgent=yesにすると、ssh-agentの実行時に自動的に鍵を追加する。
* UseKeychain=macOS専用。OSのキーチェーンからパスフレーズの検索を試みる。
* IdentityFile=SSH秘密鍵の絶対パス。デフォルトは~/.ssh/id_rsa。
上記3点で自動入力を試みる。
macOSで行う分には上記だけでパスワードは聞かれない。これをリモートでもやりたいなら、ssh-agentに登録が必要。
ログイン時に1回実行してくれたらいいので、ログインシェルの設定の~/.bash_profileに以下を記述。
echo 'ssh-add --apple-use-keychain' >>~/.bash_profile
これで端末の起動時に鍵を自動登録してくれるので、リモートでもパスフレーズを要求されない。


====== FastCGI ======
===== ssh_config =====
[https://help.coreserver.jp/faq/ よくある質問 | サポート | レンタルサーバー CORESERVER(コアサーバー)]
[https://linux.die.net/man/5/ssh_config ssh_config(5): OpenSSH SSH client config files - Linux man page]


CORESERVERでFastCGIの実行。
重要な設定・構文がある。


/public_html/.fast-cgi-bin/ 内のphpXX.fcgiを編集。コントロールパネルのPHP設定でバージョンを指定。その後該当のphpXX.iniが対応公開ディレクトリーの処理スクリプトになる。
====== TOKENS ======
macのman ssh_configに詳しい。


trac.fcgiをphp81.fcgiに改名して、その後バージョンをコントロールパネルからphp81にする。これでOK。
使用可能な指令が限定されている。


シンボリックリンクのほうがいいか。
HostName (Macのみ)
cd ~/public_html
cp php81.fcgi php81.fcgi.old
ln -fns ../trac/cgi-bin/trac.fcgi php81.fcgi
これだとダメ。


ChatGPTに記載のあった.htaccessをtrac.gnusocial.jpに配置したらそれで動作した。CORESERVERのFastCGIはPHPのみの模様。
* %h=リモートホスト名。Hostの指定部。
RewriteEngine On
* %p=リモートポート。
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /cgi-bin/trac.cgi/$1 [L]
これでtrac.gnusocial.jpを開くと開けた。


ただし、基本のURLパスが [https://trac.gnusocial.jp/cgi-bin/trac.cgi/timeline<nowiki>] のようにcgiのパスがつくようになる。</nowiki>
====== WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! ======


なんか違う気がする。
* [https://www.niandc.co.jp/tech/20150729_2464/ ssh接続をする際に「WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!」と出てつながらない|テクニカルブログ|日本情報通信株式会社]
* [https://qiita.com/hnw/items/0eeee62ce403b8d6a23c 「SSHホスト鍵が変わってるよ!」と怒られたときの対処 #SSH - Qiita]


元々の.fast-cgi-bin/php81.fcgiにtrac.fcgiのシンボリックリンクを配置した後。trac.gnusocial.jpにindex.phpを配置したら動作した?パスにindex.phpが入るようになったが。
ssh example.comなどを実行すると、IPアドレスの振り直しなどで、ホストの公開鍵が変わっていた場合、中間者攻撃への対策として失敗する。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!    @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
SHA256:.
Please contact your system administrator.
Add correct host key in /Users/z.ken.senoo/.ssh/known_hosts to get rid of this message.
Offending RSA key in /Users/z.ken.senoo/.ssh/known_hosts:1
Host key for [example.com]:3023 has changed and you have requested strict checking.
Host key verification failed.
Connection closed by UNKNOWN port 65535
Connection closed by UNKNOWN port 65535


https://chatgpt.com/c/6758c79e-f2e4-800b-88e2-7eab678f03f2
$HOME/.ssh/known_hostsの該当行を削除すれば解決する。以下のコマンドでも対応してくれる。
ssh-keygen -R example.com


==== curl ====
HTTPの通信のコマンドラインでの確認でよく使う。


== Shell ==
===== Basic =====
[https://curl.se/docs/tutorial.html curl - Tutorial]
* -X: メソッド指定
* -d/--data-urlencode: リクエストボディー (key=value)を指定。-X POSTも自動指定になる。
curl -H "Content-Type: application/json" -d '{"name":"佐藤", "mail":"sato@example.com"}' localhost:5000/api/v1/users
JSONで送信する場合、ヘッダー指定が必須。


=== Shell Command Language ===
<nowiki>*</nowiki>-F: multipart/formのform指定。
curl -F "coolfiles=@fil1.gif;type=image/gif,fil2.txt,fil3.html"
  <nowiki>http://www.example.com/postit.cgi</nowiki>
@でfilename相当の指定。;でmime typeも指定できる。


==== Compound Commands ====
@/</;type=自体を送信したい場合、-Fではなく、--form-stringを指定する。
[https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/utilities/V3_chap02.html#tag_18_09_04 Shell Command Language]


===== Case Conditional Construct =====
===== curl: (60) SSL certificate problem: self-signed certificate =====
case word in
Ref: [https://linuxfan.info/curl-insecure curlで「自己署名証明書」を受け入れるには【curl: (60) SSL certificate problem: self signed certificate】 | LFI].
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac


* 未マッチで終了ステータス0。
--insecureオプションを指定すると、localhostなどでの自己署名証明書を許可する。
* pattern部分: シェル展開が有効。他はglob。
* |でOR検索相当。
* 最後のパターンの;;は省略可能。if文のようにも使える。
* 全パターンの捕捉は最後に*。空でもマッチする。?は最低1文字必要。


BREでは未対応な|のORマッチに対応しているのが最大の特徴。文法なのでコマンドを実行せず早い。grepを使わずにできるだけこちらを使ったほうがいい。
===== curl: Failed writing body =====
[https://askubuntu.com/questions/1449492/right-after-piping-to-head-tail-curl-23-failure-writing-output-to-desti pipe - Right After piping to "head"/"tail": "curl: (23) Failure writing output to destination" - Ask Ubuntu]


=== ワイルドカード ===
以下のようにhead -n 1を指定するとcurlがエラーを出力する。
ワイルドカードで.始まりのファイルをマッチさせたい。
curl -H "Content-Type: application/json; charset=utf-8" -H "X-HD-apitoken:$TOKEN"        -d "{\"dbSchemaId\":$dbSchemaId, \"limit\":1, \"offset\":$offset}"        <nowiki>https://$DOMAIN/$ACCOUNT/api/csvexport/version/1.0</nowiki> | head -n 1


以下ならマッチするが、ブレース展開 (brace expansion) はPOSIX shでは使えなかった気がする。
curl: Failed writing body
echo {.*,*}
curlは標準出力に全部書き込めたかチェックしているようで、head -n 1で切り捨てたらcurlはエラーになる。
 
対策は、curl -sで出力を抑制するとのこと。これで解決。
 
==== Teleport ====


=== BOM ===
* [https://goteleport.com/docs/connect-your-client/teleport-connect/ Using Teleport Connect | Teleport Docs]
[https://stackoverflow.com/questions/3127436/adding-bom-to-utf-8-files unicode - Adding BOM to UTF-8 files - Stack Overflow]
* [https://speakerdeck.com/gree_tech/greetechcon2023-session-a6 SSH から Teleport へ - Speaker Deck]


ExcelでUTF-8ファイルを開けるように、UTF-8のBOMをファイルにつけたい。
踏み台サーバー (Jump server/Jump host) をよりよく管理するためのサーバーソフトウェア。
printf '\xEF\xBB\xBF' > with_bom.txt
上記コードでBOMを最初に書き込んで、後は追記する。


=== awk ===
アクセスログなどを一元管理できる。商用版とオープンソース版がある。
[https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/ The Open Group Base Specifications Issue 7]


==== 変数 ====
基本的にteleportのサーバーを一度経由して、各種の踏み台サーバーにアクセスする。経由先が1個増えるが、そのおかげで監査ログを取得できたり、権限などを一括管理できる。


===== 特別 =====
ただ、teleportで監査ログを残すには、基本的にtshを経由する必要があり、既存のIDEなどのssh想定のソフトだと工夫が必要。tsh経由でやったり、rsyncで間にtshを挟むような工夫が必要。
* NF: 列数。列の全表示などで使う基本的で重要な変数。
* NR: 行番号。


===== スコープ =====
===== tsh =====
[http://www.fukano.jp/study_of_awk/basic/basic08.htm 変数のスコープ]
teleportのコマンドラインクライアント。


関数の仮引数のみ、ローカル変数扱いで、それ以外はグローバル変数。
tsh loginでteleportにログインする。


==== 文/statement ====
環境変数


* actions
[https://goteleport.com/docs/reference/cli/tsh/ tsh CLI reference | Teleport Docs]
** if/else
** while/do...while/for
** break/continue
** delete
** next
** exit
* output
** print
** printf


==== 関数 ====
* TELEPORT_PROXY: teleportプロキシーサーバーのアドレス。重要。


===== 組込関数 =====
===== ProxyJump+ProxyCommand =====
How To Use SSH ProxyJump and SSH ProxyCommand


* Arithmetic
https://goteleport.com/blog/ssh-proxyjump-ssh-proxycommand/
** atan2
** cos
** sin
** exp
** log
** sqrt
** int
** rand
** srand
* String
** gsub
** index
** length
** match
** split
** sprintf
** sub
** substr
** tolower
** toupper
* I/O
** close
** getline
** system


print/printfは関数ではなく、statement/文扱い。
~/.ssh/config のProxyJumpとProxyCommandの違いを整理する。


==== ヘッダー出力、列別最大長さ出力。 ====
どちらも中間サーバーを経由したリモートサーバーアクセスの指令。
<nowiki>awk -F, '{if(NR==1) print $0} {for(i=1; i<=NF; ++i){if (line[i] < length($i)) line[i] = length($i)}} END {for (i=1; i<=NF; ++i) {printf line[i]","}}' data/101542.csv</nowiki>


==== CSV ====
* ProxyJump: 最も簡単な方法。OpenSSH v7,5以上で使用可能。中間サーバーでポート転送対応が前提条件。ProxyJumpは内部でProxyCommandを使う。
[https://qiita.com/ko1nksm/items/19407c1c53cbbc50569a シェルスクリプトの実験のために作った POSIX 準拠 awk 実装の CSVパーサー (RFC4180対応) #ShellScript - Qiita]<syntaxhighlight lang="awk" line="1">
* ProxyCommand: ProxyJump搭乗前の方法。中間サーバーを介して標準入力と標準出力を転送して機能。
# csvparser.awk


## Usage
ProxyJumpの方が現代的だが、ProxyCommandの方が柔軟性が高い。
# awk -f csvparser.awk data.csv


# CSV の論理的な一行毎に呼び出されるコールバック関数(サンプル)
ProxyJumpの使用例。
# row: 行番号(最初の行は1) len: フィールド数 fields: フィールドデータ
{| class="wikitable"
function callback(row, len, fields,  col, field) {
|<code>ssh -J <jump server> <remote server>ssh -J <jump server1>,<jump server2>,<jump server3> <remote server></code>
    for ( col = 1; col <= len; col++ ) {
|}
        field = fields[col]
ProxyCommand
        gsub(/\\/, "&&", field)  # \ は \\ にエスケープする
{| class="wikitable"
        gsub(/\n/, "\\n", field) # 改行は \n にエスケープする
|<code>ssh -o ProxyCommand="ssh -W %h:%p <jump server>"</code> <code><remote server></code>
        print row ":" col " " field
|}
    }
~/.ssh/configの例。
}
{| class="wikitable"
|<code>Host remoteserver</code>
 
<code> HostName 192.168.200.200</code>
 
<code> User dev</code>
 
<code> IdentityFile ~/.ssh/<your_key></code>
 
<code> Port 2048</code>
 
 
<code> ## sample for</code> <code>ProxyJump</code>
 
<code> ProxyJump user@<jumpserver></code>
 
 
<code> ## sample for</code> <code>ProxyCommand</code>


BEGIN { row = max_idx = 0 }
<code> ProxyCommand ssh -W %h:%p <jumpserver></code>
{
|}
    idx = 0
ssh remoteserver で<jumpserver> 経由でremoteserverに接続できる。
    sub(/\r$/, "")
    while ($0 != "") {
        if (match($0, /^(["]([^"]|["]["])*["]|[^,"]*)(,|$)/)) {
            fields[++idx] = ""
        } else if (match($0, /^["]/)) {
            fields[++idx] = substr($0, 2)
            for (;;) {
                if (getline == 0) exit 1
                sub(/\r$/, "")
                if (match($0, /^([^"]|["]["])*["](,|$)/)) break
                gsub(/["]["]/, "\"")
                fields[idx] = fields[idx] "\n" $0
            }
            fields[idx] = fields[idx] "\n"
        } else {
            exit 1
        }
        field = substr($0, RSTART, RLENGTH)
        $0 = substr($0, RSTART + RLENGTH)
        lastcomma = sub(/,$/, "", field) > 0
        gsub(/^["]|["]$/, "", field) && gsub(/["]["]/, "\"", field)
        fields[idx] = fields[idx] field
    }
    if (lastcomma) fields[++idx] = ""
    while (idx < max_idx) delete fields[max_idx--]
    callback(++row, idx, fields)
    max_idx = idx
}


</syntaxhighlight>awkのCSVパーサー。先頭のBOMはあると認識できないので、tail -c +4でBOMを除外して使う。
一般的に、ProxyJumpが推奨される感がある。ただ、teleportを導入している場合、ProxyJump/ProxyCommandを使うと、tshを経由していないのでteleportにログが残らないらしい。
tail -c +4 data/101543.csv | awk -f csvparser.awk


=== Other ===
===== tsh経由ssh =====
ProxyJump/ProxyCommandを使わない場合、以下の形式でtshを使ってアクセスするのが基本。
tsh ssh 踏み台サーバーホスト名
tsh sshでteleportサーバーが管理している踏み台サーバーが見えるので、そこに接続できる。tshの後のsshは基本的に通常のsshと同じなので、sshの後にsshのコマンドを連鎖でき、対象サーバーにも一発でアクセスできる。
tsh ssh -At <jump host> ssh -A <target host>
-tでttyに繋いで標準入出力を接続。-Aはフォワーディング。ローカルのssh-addの情報などを連携できる。


==== binary ====
<jump host>の~/.ssh/configを用意しておくことで、<target host>にホスト名を指定したりできる。
[https://qiita.com/ko1nksm/items/dc8f247cdc5b7b58b736 POSIX準拠のシェルスクリプトでバイナリデータを扱う #Bash - Qiita]


バイナリーデータの読込はodコマンド。なければhexdump。
ProxyJump/ProxyCommandと異なり、これだとちゃんとログを残せる。


書込はprintf。
===== tsh経由scp =====


head/tailの-cはPOSIXで使えたか?
* [https://goteleport.com/blog/teleport-files/ Teleport Files with SCP]
* [https://goteleport.com/docs/connect-your-client/tsh/ Using the tsh Command Line Tool | Teleport Docs]


==== root ====
tsh経由の踏み台サーバーへのファイル転送はやや工夫が必要。


===== リダイレクト出力 =====
tsh scpというコマンドが一応ある。が、これはネストなどには未対応。やる場合、以下のように2回実行になる。
[https://blog.shaba.dev/posts/redirect-with-sudo sudo権限でリダイレクト処理を行ってファイルに書き込む方法]
FR=test.file TO=/path/to/test.file
tsh scp $FR <jump host>:$TO; tsh ssh -At <jump host> scp $TO <target host>:$TO
高ではなく、rsyncを使えば一発でいける。
rsync -e "tsh ssh -A <jump host> ssh" ./test.file <target host>:~/
これが基本。


リダイレクトはログインユーザーの権限でなされるらしく、root権限のある場所にファイル出力できない。
====== PhpStorm ======
[https://goteleport.com/docs/enroll-resources/server-access/guides/jetbrains-sftp/ JetBrains SFTP | Teleport Docs]


teeコマンドでやる。
teleportの公式にマニュアルがあるが、記述が非常に不親切。これだと踏み台サーバーにしかアクセスできない。その先にアクセスできない。
pwd | sudo tee out.dat
teeコマンド実行する側でsudoが必要。


== cmd.exe ==
多段SSHの設定を残しておいて、ファイル転送だけrsyncで行う形になる。


=== Control block ===
PhpStormのSSH configurationsのホスト名がスクリプトの引数に渡されるので、踏み台からAWSにsshでログインするホスト名やパソコンの~/.ssh/configのHostとの一致必要な点に注意する。
USERNAME=
IPV4=
VPCID=
cat <<-EOT >>~/.ssh/config
Host $VPCID
  ForwardAgent yes
  User $USERNAME
  ServerAliveInterval 30
  SendEnv -LC_* -LANG
  ProxyJump $USERNAME@teleport.security:3023
   
Host $USERNAME
    ForwardAgent yes
    ProxyJump $VPCID:22
    User $USERNAME
    Hostname $USERNAME.example.com
    ServerAliveInterval 30
    SendEnv -LC_* -LANG
   
Host $USERNAME.$VPCID
    # for automatic upload by PHPStorm
    LocalForward 22224 $USERNAME.$VPCID:22
    # for XDebug
    RemoteForward 9000 localhost:9000
    ForwardAgent yes
   
Host db-*
  HostName $IPV4
  LocalForward 3307 localhost:22
  ProxyCommand ssh $VPCID -W %h:%p
  ForwardAgent yes
   
Host *
    AddKeysToAgent yes
    PasswordAuthentication no
    User $USERNAME
    ForwardAgent yes
    ServerAliveInterval 30
    IdentityFile ~/.ssh/id_ed25519
    # for macOS
    UseKeychain yes
EOT
こんな感じの多段SSHの設定を用意。
踏み台サーバーにも同じホスト名でアクセスできるように、以下のような内容の~/.ssh/configをまだならば設定しておく。
{| class="wikitable"
|<code>AWS_HOSTNAME=</code>


==== for ====
<code>IPV4=</code>
あくまでコマンド。


===== nest =====
<code>VPCID=</code>


* [https://chicagopile1-75.hatenablog.com/entry/2018/05/23/143502 バッチファイルで2重ループ - ハムスターに飼われる院生のブログ]
<code>tsh ssh -A $VPCID "cat >>~/.ssh/config"</code> <code><<-EOT</code>


* [https://web.archive.org/web/20230602041631/https://jj-blues.com/cms/wantto-useloop/ web.archive.org/web/20230602041631/https://jj-blues.com/cms/wantto-useloop/]
<code>Host $AWS_HOSTNAME</code>


ネストはできない。二重ループしたければ、関数にしてそれを呼び出す。
<code> HostName $IPV4</code>


=== bitsadmin ===
<code>EOT</code>
Windowsでのファイルダウンロードコマンド
|}


Windows 7以降ではbitsadminコマンドがあり、これがwget相当となる。


書式:
rsync executable
bitsadmin /transfer <job name> <URL> <output path>
<job name>と<output path>は必須なので注意する。


=== certutil ===
rsyncで使用する (-eオプション)、以下の内容のシェルスクリプトを作成して実行権限を付与して任意の場所 (例: ~/project/tsh_ssh.sh) に配置する。
Windowsでのハッシュの確認に使える。
{| class="wikitable"
certutil -hashfile file
|<code>cd ~/project/</code>


SHA1 ハッシュ (対象 C:\moconavi\windows\Moconavi\ext\chromium\moconavium.exe):
<code>cat <<-'EOT'</code> <code>>tsh_ssh.sh</code>
e0da85b04b6970ac1f0c33db7a9ad607fdbd44eb
CertUtil: -hashfile コマンドは正常に完了しました。


=== rlogin.cmd ===
<code>tsh ssh -A <jump host> ssh $@</code>
コマンドキーの送信を自動化できる?
rem rlogin.cmd
@Echo off
Set SERVER=192.168.0.0
Set USERNAME=
Set PASSWORD=
Cmdkey /generic:TERMSRV/%SERVER% /user:%USERNAME% /pass:%PASSWORD%
Start mstsc /v:%SERVER%
Timeout 5
Cmdkey /delete:TERMSRV/%SERVER%


=== 実行中プロセスのパスの確認 ===
<code>EOT</code>
出典: [https://superuser.com/questions/768984/show-exe-file-path-of-running-processes-on-the-command-line-in-windows Show EXE file path of running processes on the command-line in Windows - Super User]。
wmic process get ProcessID,ExecutablePath
wmic process where "name='mysqld.exe'" get ProcessID, ExecutablePath
wmic process where "name='mysqld.exe'" get ProcessID, ExecutablePath /FORMAT:LIST


=== 簡易編集モード/挿入モード ===
<code>chmod +x tsh_ssh.sh</code>
|}


* [https://softantenna.com/blog/windows-10-command-prompt-no-stop/ 【Tips】Windows 10のコマンドプロンプトが意図せず止まってしまう問題を回避する方法 | ソフトアンテナ]
* [https://superuser.com/questions/419717/windows-command-prompt-freezing-randomly Windows command prompt freezing randomly - Super User]


Windows 10のcmd.exeは [簡易編集モード] が有効になっており、コマンドプロンプトを左クリックすると、テキストの選択が始まる。テキスト選択中はコマンドの実行が止まる。長時間かかるコマンドの実行中に誤操作で止まると困るので、これは無効にしたほうがよい。


cmd.exeを起動-左上のアイコンをクリック-[規定値]/[プロパティ]-[オプション]-[□簡易編集モード] を選ぶ。
PhpStorm設定


そのほか、 <code>git log</code> のような制御が移るコマンドを実行してしばらくすると、操作できなくなる。
PhpStormで以下を設定する。


[□挿入モード] にすると回避できる模様。
* [Tools]-[Deployment]-[Configuration]
* [+]-[SFTP]
* [Create New Server]-[New server name: 任意の名前 (例=rsync)]-[OK]
* [Connection] タブを以下に設定。
*# Type=SFTP
*# SSH configuration=以下を設定。
*## Host: <ホスト名> (例: ~/.ssh/configと踏み台サーバーの~/.ssh/configのホスト名と同じにする)
*## User name: ユーザー名
*## Port: 22
*## Authentication type: OpenSSH config and authentication agent
*# Root path=転送先のベース。
*# [☑️Use Rsync for download/upload/sync]
*# Rsync Settings=以下を設定。
*## Shell executable path=tsh_ssh.shのパス (例=~/project/tsh_ssh.sh)
* [Mappings] タブを以下に設定。
*# Local path: ローカルパソコンのディレクトリー
*# Deployment path: /
*# Web path: /
* [Settings]-[Build, Execution, Development]-[Development]-[Options]-[Upload changed files automatically to the default server]=[On explicit save action]
*# ☑️Delete remote files when local are deleted


== Web ==
以上で完了。後は同期したいファイルをPhpStormで開いて、右クリック-[Deployment]-[Upload to]/[Download from] でファイル転送できる。


=== URL ===
[☑️Use Rsync for download/upload/sync] のチェックを外せば、rsyncを使わないファイル転送になる。


==== クエリー配列 ====
=== Wireshark ===


* [https://shinkufencer.hateblo.jp/entry/2019/05/18/163912 クエリストリングで配列を表現をするケースをざっと調べる - コード日進月歩]
==== TLS ====
* [https://qiita.com/s4kd0R/items/8a11d88099008bb1e9dc PHPでクエリパラメータから配列を受け取る物語 #JavaScript - Qiita]
Ref: [https://www.toyo.co.jp/onetech_blog/articles/detail/id=36994 SSL/TLSの復号#1 ~Wiresharkの設定~ | 東陽テクニカ | “はかる”技術で未来を創る | ワン・テクノロジーズ・カンパニー].
* [https://www.php.net/http_build_query PHP: http_build_query - Manual]


やり方がいくつかある。
Wiresharkで通信パケットを確認する場合、デフォルトでTLSで暗号化されているので、内容がわからない。WiresharkでTLSに対応しておく必要がある。


# CSV文字列で受取後分割: <nowiki>https://www.sakdor.net/test/?var=1,2,3</nowiki> explode(",",$_GET[var]);
[Preferences]-[Protocols]-[TCP] を選ぶ。
# 配列添字
## http://www.sakdor.net/test/?var&#x5B;&#x5D;=1&var&#x5B;&#x5D;=2&var&#x5B;&#x5D;=3
## http://www.sakdor.net/test/?var&#x5B;a&#x5D;=1&var&#x5B;b&#x5D;=2&var&#x5B;c&#x5D;=3
## http:www.sakdor.net?var[0]=1&var[1]=2&var[2]=3


データが決まっているならcsvがシンプル。
* ☑Allow subdissector to reassemble TCP stream
* ☑Reassemble out-of-order semgemnts


=== HTTP ===
上記をチェックしておく。デフォルトでチェックされていた。
[https://www.rfc-editor.org/rfc/rfc9110.html RFC 9110: HTTP Semantics]


==== Content-Disposition ====
続いて、セッションごとのPre-Master Secretを登録する。
[https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Content-Disposition Content-Disposition - HTTP | MDN]


[https://datatracker.ietf.org/doc/html/rfc6266 RFC 6266 - Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)]
Chrome/Firefoxだと、環境変数SSLKEYLOGFILEを設定すれば、このファイルにTLSセッションキーを出力するので、これをWiresharkで読み込むことで、復号対応する。
Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"
filenameでファイル名を指定する。ここの値は二重引用符で囲む。スペースを含む場合に必須になる。


==== multipart/form-data ====
以下のコマンド相当で、任意のファイル・場所にログファイルを指定する。
rfc7578
export SSLKEYLOGFILE=/tmp/sslkey.log
Macだとlaunchctlで設定しておくといい。これでWebブラウザー経由の場合は見えるようになる。


* [https://datatracker.ietf.org/doc/html/rfc7578 RFC 7578 - Returning Values from Forms: multipart/form-data]
=== Security ===
* [https://qiita.com/sivertigo/items/14957200af5ad953d63b Multipart/form-dataの仕様メモ #HTTP - Qiita]


ファイルアップロード用のMIME type。
==== DoS攻撃 ====
いくつか対策方法がある。


リクエストヘッダー
* [https://lite.ip2location.com/ip-address-ranges-by-country?lang=ja 国別のIPアドレス範囲]
Content-Type: multipart/form-data; boundary=--hogehoge
* [https://rakko.tools/tools/11/ IPアドレスから住所検索:国、地域の特定 | ラッコツールズ🔧]
リクエストボディー
--hogehoge
Content-Disposition: form-data; name="user_name"
Content-Type: text/plain
test
--hogehoge
Content-Disposition: form-data; name="email"
sample@mail.com
--hogehoge
Content-Disposition: form-data; name="gender"
male
--hogehoge
Content-Disposition: form-data; name="user_profile" filename="image.jpeg"
Content-Type: image/jpeg
\xff\xd8\....
--hogehoge--
ヘッダーでmultipart/form-dataを明記して、ボディーでデータを指定する。


[https://weblabo.oscasierra.net/curl-post/ curlコマンドでPOSTする, 様々な形式別メモ |]
サーバーログにIPアドレスが残るから、それで攻撃元の国を特定して、該当国を一括アクセス拒否。これが効果あるかもしれない。


curlでの送信理由。
攻撃元の国は途上国とかが多いだろうから。IPアドレスは簡単に変更できるが、国を変えるのはたいへんだろう。


-Fで送信データをname=data形式で指定する。ファイルの内容を指定する場合、@filenameで指定する。これを指定すると、リクエストボディーのfilename扱いにしてくれる模様。-Fを指定すると、-H 'Content-Type: multipart/form-data'が自動付与される。たぶん、-dと同様に-X POSTもつく。
==== バリデーションの実装 ====
curl -X POST -F file1=@/var/tmp/sample.jpg <nowiki>https://xxxxx.net/xxxxxx</nowiki>
データとテキストを同時送信したい場合、-Fで複数指定する。
curl -X POST -F 'age=30' -F file1=@/var/tmp/sample.jpg <nowiki>https://xxxxx.net/xxxxxx</nowiki>
curlだと上記のboundaryなどをうまくやってくれるのだと思う。


リクエストボディー全体をファイルデータにする場合。
* [https://teratail.com/questions/81861 フロント側で入力チェックをしていればサーバー側では入力チェックは必要ない?]
curl -X POST -H 'Content-Type: image/jpeg' --data-binary @/var/tmp/sample.jpg <nowiki>https://xxxxx.net/xxxxxx</nowiki>
* [https://qiita.com/mi2__user/items/f2f415ccbb0a625c8647 フロントエンドの"バリデーション"は最低限の方がいいらしい。 #TypeScript - Qiita]


=== IP address ===
基本的に、バックエンドで主にチェックして、フロントエンドはUXの向上目的で実装する。データの重複チェックはDBアクセスが必要だったりするから。また、API経由などフロントがそもそもないケースもある。
出典: [https://glocalnet.jp/vpn/topix/archives/67#:~:text=%EF%BC%94%EF%BC%8E%E5%9B%BA%E5%AE%9AIP%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%AE%E5%8F%96%E5%BE%97%E6%96%B9%E6%B3%95%20%E5%8F%96%E5%BE%97%E6%96%B9%E6%B3%95%E3%81%AF%E4%B8%BB%E3%81%AB3%E3%81%A4%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82,%E3%83%BB%E5%A5%91%E7%B4%84%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E3%83%97%E3%83%AD%E3%83%90%E3%82%A4%E3%83%80%E3%81%A7%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A8%E3%81%97%E3%81%A6%E7%94%B3%E3%81%97%E8%BE%BC%E3%82%80%E6%96%B9%E6%B3%95%20%E3%83%BB%E5%9B%BA%E5%AE%9AIP%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%AB%E5%AF%BE%E5%BF%9C%E3%81%97%E3%81%A6%E3%81%84%E3%82%8BSIM%E3%82%92%E5%A5%91%E7%B4%84%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%20%E3%83%BBVPN%E3%82%92%E5%88%A9%E7%94%A8%E3%81%97%E3%81%9F%E5%9B%BA%E5%AE%9AIP%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%AE%E6%8F%90%E4%BE%9B%E4%BC%9A%E7%A4%BE%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95 固定IPアドレスの取得方法 ~実は簡単!フリーランスの方も必見です~|VPN活用日記|トピックス|グローカルネットの快適VPN【公式】| 株式会社グローカルネット]。


自宅サーバーを行う際、固定IPアドレスが必要になる。
ただ、社内システムのような、画面経由でしか使わない。悪者がほぼいないと思われるケースは、フロントエンドでの検証だけでも十分に感じる。


取得方法がいくつかある。
==== 二重送信 ====


* 契約しているプロバイダでオプションとして申し込む方法
* [https://www.youfit.co.jp/archives/4545 フォームの二重送信を防止する方法 - 福岡・東京のシステム開発会社 (株)ユーフィット]
* 固定IPアドレスに対応しているSIMを契約する方法
* [https://qiita.com/syobochim/items/120109315f671918f28d さいきょうの二重サブミット対策 #JavaScript - Qiita]
* '''VPNを利用した固定IPアドレスの提供会社を利用する方法'''


VPNの固定IPアドレスが安いらしい。ryoかsuwakoが解説していた気がする。
submitボタンのダブルクリック、リロード、ブラウザーバック・フォワードなど、フォーム周りで注意が必要な保安要素がある。


=== Authentication ===
# ボタン連打
認証方式がいくつかある。HTTPで定義される認証方式 (HTTP認証) が有名。
# ブラウザーバック
# リロード (PRG)


==== Basic認証 ====
項目ごとにすべき対策が異なる。
出典: [https://ja.wikipedia.org/wiki/Basic%E8%AA%8D%E8%A8%BC Basic認証 - Wikipedia]。
 
===== 連打 =====


Authorization HTTPヘッダーにBasicのあとに [username:password] をBASE64でエンコードして送信する認証方式。
* [https://www.youfit.co.jp/archives/4545 フォームの二重送信を防止する方法 - 福岡・東京のシステム開発会社 (株)ユーフィット]
GET /private/index.html HTTP/1.1
* [https://qiita.com/syobochim/items/120109315f671918f28d さいきょうの二重サブミット対策 #JavaScript - Qiita]
Host: example.com
* [https://codezine.jp/article/detail/769 JavaScriptを利用してフォームの二重送信を防止する|CodeZine(コードジン)]
Authorization: Basic cm9vdDpwYXNzd29yZA{{=}}{{=}}
* [https://blog.nisesagi.com/3150/ JavaScriptでformの2重送信を防止する | にせサギ ネットサギ体験ブログ]
盗聴や改ざんが簡単だが、シンプルという利点がある。
* [https://yutaihara.com/archives/569 Javascriptで送信ボタン二度押しによる二重送信を防止する方法 | Yuta Ihara.com]


==== OAuth ====
基本は、ボタンのsubmitのイベント内でdisabled=trueでの無効化。
Ref


* [https://ja.wikipedia.org/wiki/OAuth OAuth - Wikipedia]
似た考え方で、スプラッシュのモーダル表示もあり。これがわかりやすいかもしれない。
$("form").submit(function() {
  var self = this;
  $(":submit", self).prop("disabled", true);
  setTimeout(function() {
    $(":submit", self).prop("disabled", false);
  }, 10000);
});
停止にしたら、二度通せなくなるので、タイムアウトで戻すとよい。


OAuth (オーオース) 権限の認可のための標準。OAuth 2.0が最新の標準。
=== Browser ===


以下が登場人物。
==== Chromium ====


* resource owner: あるサイトのユーザー。
===== Extension =====
* resource server: あるサイトのユーザーのデータの保有サーバー。
Chromme系で愛用拡張機能を列挙する。
* clent: クライアントアプリ。リソースサーバーのデータを使用したい。
* authorization server: クライアントにサイトへのアクセスを認証するサーバー。アクセストークンを発行して行う。


アクセストークンが実質的なパスワードのようなものだが、resource serverのパスワードを直接渡していない点が重要な違い。パスワードを直接渡さないことで、機能別に権限を細かく利用可否を制御できる。
* [https://chromewebstore.google.com/detail/create-link/gcmghdmnkfdbncmnmlkkglmnnhagajbm Create Link]:


処理の流れ。
==== devtool/開発者ツール ====


# client->resource owner: Authorization Request。ここでユーザーが手操作でアクセスを承認する。
===== イベントリスナー =====
# client<-resource owner: Authorization Grant。
[https://yuzu441.hateblo.jp/entry/2016/12/12/120000 要素に設定されているイベントを調べよう - ゆずめも]
# client->authorization server: Authorization Grant。承認された情報でアクセストークンを要求。
# client<-authorization server: Access Token
# client->resource server: Access Token。アクセストークンでアクセス。
# client<-resource server: Access Token


Consumer Key/Secret: アプリ識別用のID/PW。
[Elements]-[Event Listeners]-[handler]-右クリック-[Show function definition] でイベントリスナー関数の定義を確認できる。


Access Token: サイトにアクセスするためのパスワード。
===== イベント監視 =====
[https://stackoverflow.com/questions/3787555/how-to-find-out-which-javascript-events-fired How to find out which JavaScript events fired? - Stack Overflow]


=== API ===
monitorEvent関数で監視できるらしい。他に、FirefoxのFirebugのlog eventsでも監視できるらしい。


==== 複数レコードの登録 ====
===== Network conditions =====
[https://buddypia.com/2021/11/14/%E8%A4%87%E6%95%B0%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89api%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%AA%BF%E3%81%B9%E3%81%A6%E3%81%BF%E3%81%9F%E8%A9%B1/ 複数レコードの登録・更新・削除のREST APIについて調べてみた話(+@ Graph API) - junode | 個人開発ブログ]
開発者ツールの[Network]タブを開いてリロードしても、[No internet]と表示されることがある。


既存のAPIは単一リソースの処理しかないことが多い。JavaScriptなどで単一リソースを何回も呼べばいいというのはそうだけど、JavaScriptなしでは動作しない。一括処理用のAPIを作るしかなくないか?
これはオプション設定の問題。上のツールバーの[Disable cache]の右が[Offline] だとこうなる。これを[No throttling]にすると解決する。クリックミスだと思われる。


[https://www.yamarkz.com/blog/rest-web-api-practice REST WebAPIのプラクティス | yamarkz.com]
==== Safari ====


delete_bulkなどのような一括処理用のAPIを作るしかない。内部的には単一処理のAPIを作る感じだったとしても。
===== Windows Safari =====


==== パラメーター ====
* [https://web.archive.org/web/20220220134447/https://jp.techcrunch.com/2012/07/27/20120725apple-safari-for-windows-ends/ Appleは静かにWindows版Safariの開発から手を引いてしまったのだろうか? | TechCrunch Japan]
[https://stackoverflow.com/questions/25385559/rest-api-best-practices-args-in-query-string-vs-in-request-body json - REST API Best practices: args in query string vs in request body - Stack Overflow]
* [http://web.archive.org/web/20120728130701/https://support.apple.com/kb/DL1531 Safari 5.1.7 for Windows]


パラメーターの指定に3種類ある。
一応ある。2012-05-09のSafari 5.1.7までWindows版が提供されていた。DL1531。


# リクエストボディー
===== 開発者ツール =====
# クエリー
[https://www.e-bird.biz/blog/dev-ios/ PCでスマホサイトを見る方法 – Safari編|東京渋谷のWeb制作会社・ホームページ制作会社|株式会社イー・バード]
# パス


パスはIDなどを指定する場合だけわかりやすい。それ以外のオプションはクエリーのほうがいい。
Safariの開発者ツールは癖がある。


ボディーは、通常サーバーのアップロード・ダウンロードデータとして使われる。クエリーはデータの指定に使う。
[設定]-[詳細]-[☑️Webデベロッパ用の機能を表示]


この原則に従うとシンプルだろう。
[開発]-[レスポンシブデザインモードにする]


* URIには長さの制限がある。
=== Other ===
* ボディー
** 引数が非常に多い場合。
** 画像などバイナリーデータ。
** キー・値構造を持たない場合。
* クエリー文字列
** 引数を簡単に確認できる。
** 共通の引数の場合。


==== 検索機能のGET/POST ====
==== Tool ====


* [https://stackoverflow.com/questions/20550514/post-or-get-in-a-search-form .net - POST or GET in a search form? - Stack Overflow]
* [https://web-toolbox.dev/ Web ToolBox | 開発者向けのオンラインツール]
* [https://tm-webtools.com/ TM - WebTools]


検索機能にGETとPOSTのどちらを使うか?という議論がある。
いくつかWeb関係の開発で役立つツール集を公開しているサイトがある。


データ登録するわけなじゃないのだから、GETがいいんじゃない?
==== localhost ====


POSTだと、JSONをそのまま送れるので、複雑なケースに対応できる。特に、配列の送信が重要。
* [[wikipedia:Special-use_domain_name|Special-use domain name - Wikipedia]]
* [https://ja.wikipedia.org/wiki/.localhost .localhost - Wikipedia]


GETのほうが検索条件をブックマークにできたり、URLを共有できるので、基本は便利。
RFC 6761 で規定。RFC 2606<nowiki/>で予約。DNSに登録されることはないため、テスト目的で使用可能。ループバック (送信元にそのまま返す) インターフェイス。


ただし、検索などのパラメーターが長くなる場合、使用できない。そもそも検索でそんなに長いパラメーターというのがまずいかもしれない。2000文字あれば十分という説がある。
IPv4=127.0.0.1/IPv6=::1とされている。


==== レート制限対策 ====
== Shared Host ==


* [https://pikodon.com/note/php/api-cache/ APIの利用制限対策 | Web開発ノート]
=== Free ===
* [https://keirinomikata.zendesk.com/hc/ja/articles/4404549985945-%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E6%95%B0%E3%81%AB%E3%82%88%E3%82%8B%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%88%B6%E9%99%90%E3%81%AE%E5%AF%BE%E7%AD%96%E6%96%B9%E6%B3%95 リクエスト数によるアクセス制限の対策方法 – 請求管理ロボ ヘルプ]
無料で使用可能な共用ホスティングサービスがある。


いろいろ方法がある。
==== スタードメイン無料サーバー ====
ドメインをセットで利用する必要があるものの、スタードメインのスタードメイン無料サーバーがけっこういい。


* cronなどでデータをサーバー上 (DBなど) に定期保存して、保存データを表示させる。
[https://www.star-domain.jp/service/free_server.php 無料レンタルサーバー | スタードメイン - ドメイン取得 100円(税込)~]
* 配列を利用して、1回のリクエストでまとめて取得する。
* インターバルを設ける。
* HTTP 429/413を検知して、リトライする。


==== 指数関数的バックオフ ====
jpドメインの金額が相場の中では安い方で、それに無料サーバーがついていくる点。


* [https://docs.link.getmoneytree.com/docs/faq-rate-limiting APIレート制限は何か、どのように対処するのか?]
* ディスク容量 20GB
* [[wikipedia:Exponential_backoff|Exponential backoff - Wikipedia]]
* DB 1GB
* [https://cloud.google.com/memorystore/docs/redis/exponential-backoff?hl=ja 指数バックオフ  |  Memorystore for Redis  |  Google Cloud]
* [https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/cloud-design-patterns/retry-backoff.html バックオフパターンで再試行 - AWS 規範ガイダンス]リトライ時は以下のアルゴリズムがいいらしい。
wait_interval = base * 2^n +/- jitter


* <code>wait_interval</code> は、API が HTTP 429 で応答した場合に、システムがリクエストを再試行するまでの時間となります。
ただし、SSHやコマンドは使えないので、FTPでWordPressを展開して設置するとか、そういう簡単な使い方だけ。ただ、それでもWordPressでWebサイトを構築するくらいなら十分だと思う。
* <code>base</code> は最初の間隔、つまり最初の再試行までの待ち時間です。この値には3000msを使用することをお勧めします。
* <code>n</code> は、現在の呼び出しの前にリクエストが通らなかった数です。複数のスレッドやプロセスを使用して並行してAPIを呼び出している場合、<code>n</code>の値は現在のスレッド/プロセスにスコープされます。この値は、現在のスレッド/プロセスが、最後に成功した応答から何回 429 "Too Many Requests" エラーに遭遇したかを表します。
* <code>jitter</code> は 0 から <code>base</code> の間の乱数です。これは、複数のスレッド/プロセスが全く同時にAPIを呼び出さないように、リクエストを少しずつ分散させるために使用されます。システムが待機するたびに、この乱数値を再計算し <code>wait_interval</code> の合計に加算するか減算するか、ランダムで選択してください。


==== バックエンドとフロントエンドの分離 ====
=== CORESERVER ===
https://chatgpt.com/c/6747e923-6174-800b-8816-dd741721de45
 
==== メール ====


SPA (Single Page Application) やJAMStackの影響で、バックエンドはデータを返すだけで、画面描画はフロントエンドが全部するというのが最近の流行。
* [https://www2.bwt.jp/wiki/?Custom_Filter_of_Coreserver Custom_Filter_of_Coreserver - PukiWiki]
* [https://help.coreserver.jp/manual/v2/spam-filter/ スパムフィルターの設定 | マニュアル | サポート | レンタルサーバー CORESERVER(コアサーバー)]
* [https://help.coreserver.jp/manual/v1/customfilter/ カスタムフィルターの設定 | マニュアル | サポート | レンタルサーバー CORESERVER(コアサーバー)]


SSR (Server Side Rendering) とCSR (Client Side Rendering) の違い。フロントエンドの高度化や分業などが理由とのこと。
情報


SSRの利点。
* [https://www2.bwt.jp/wiki/?CoreServer_Mail_Custom CoreServer_Mail_Custom - PukiWiki]
* [https://bwt.blog.ss-blog.jp/2021-03-28 coreserverのメール設定:BWT Lab.:SSブログ]
* [https://qwerty.work/blog/2017/01/valueserver-spammail-filter-rule.php バリューサーバーのフィルター設定でスパムメール(迷惑メール)対策する方法 - QWERTY.WORK]
* [https://awmt.jp/dekirukana/archives/2253 コアサーバー V1にてカスタムフィルターで「ごみ箱」を指定したときの確認方法 – AWMTの、できるかな?]


* SEO
ルールが特殊なので注意する。
* 初期表示。
* 匿名。


SSRの課題。
ゴミ箱に振り分ける場合。


* サーバー負荷: データとHTML作成を同時に行うから。
順1 で[<code>./.Trash</code>] を指定
* 分散困難:


キャッシュの活用がポイントになるとのこと。
順2


=== Network ===
* 条件:  [<code>.*</code>]
* 処理:  <code>./</code>、に振り分ける


==== ssh ====
条件部分には正規表現が使えるように見える。


===== ssh-addの自動登録 =====
破棄にしないといけない。転送する場合、カスタムフィルターの中に転送を入れる。条件を.*にする。
ssh agentに秘密鍵の登録は以下のコマンド。
 
ssh-add <秘密鍵のpath>
カスタムフィルターにくせがある。
ただし、上記コマンドは再起動すると登録が消えるので毎回必要。
 
* エスケープ(\を前置する)が必要な文字は「'」「"」「|」「`」「~」「?」「!」


~/.ssh/configに以下の内容を記入しておくと、次回からkeychainから自動で読み込まれるらしい ([https://qiita.com/sonots/items/a6dec06f95fca4757d4a macOS で再起動しても ssh agent に秘密鍵を保持させ続ける二つの方法 #SSH - Qiita])。
==== Value Domain ネットde診断 byGMO ====
Host *
  UseKeychain yes
  AddKeysToAgent yes
うまくいかなかった。


[https://aifan.jp/2022/01/25/ssh-add%E3%82%92pc%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8B%E5%BA%A6%E3%81%AB%E8%87%AA%E5%8B%95%E7%9A%84%E3%81%AB%E5%AE%9F%E8%A1%8C%E3%81%95%E3%81%9B%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E8%A8%AD%E5%AE%9A/ ssh-addをPC起動する度に自動的に実行させるための設定 | AIFAN]
* [https://www.value-domain.com/information/detail/?no=20240606-1 弊社レンタルサーバー上で運用中のドメインにおける自動セキュリティ診断開始のお知らせ | お知らせ - バリュードメイン]
* [https://www.value-domain.com/security/net-de-shindan/ Value Domain ネットde診断 byGMO - バリュードメイン]


id_rsaの場合はIdentityFileを省略できるが、それ以外は指定が必要な模様。
2024-06-07 Friからバリュードメイン系の利用者に無料で提供しているセキュリティー診断ツール。
Host *
  UseKeychain yes
  AddKeysToAgent yes
  IdentityFile ~/.ssh/id_ed25519


==== curl ====
==== CGI ====
HTTPの通信のコマンドラインでの確認でよく使う。


===== Basic =====
* [https://senooken.jp/post/2020/02/21/3905/ CORESERVERでのFastCGI/CGI版PHPの利用手順 – senooken JP]
[https://curl.se/docs/tutorial.html curl - Tutorial]
* [https://help.coreserver.jp/faq/php-fast-cgi/ FastCGI版PHP 各バージョンのPHP設定方法 | よくある質問 | サポート | レンタルサーバー CORESERVER(コアサーバー)]
* -X: メソッド指定
* [https://help.coreserver.jp/faq/php-cgi/ PHPをCGIとして動かす方法を教えてください | よくある質問 | サポート | レンタルサーバー CORESERVER(コアサーバー)]
* -d/--data-urlencode: リクエストボディー (key=value)を指定。-X POSTも自動指定になる。
* [https://engineer-milione.com/create/python-execution.html レンタルサーバー各社でのPythonの実行方法まとめ]
curl -H "Content-Type: application/json" -d '{"name":"佐藤", "mail":"sato@example.com"}' localhost:5000/api/v1/users
JSONで送信する場合、ヘッダー指定が必須。


<nowiki>*</nowiki>-F: multipart/formのform指定。
CORESERVERでのCGIの設定方法がある。
curl -F "coolfiles=@fil1.gif;type=image/gif,fil2.txt,fil3.html"
{| class="wikitable"
  <nowiki>http://www.example.com/postit.cgi</nowiki>
|+CORESERVERのFastCGI版PHPとCGI版PHPの設定方法
@でfilename相当の指定。;でmime typeも指定できる。
!項目
!FastCGI
!CGI
|-
|バージョンの変更
|管理画面
|<code>.htaccess</code>内の
<code>AddHandler application/x-httpd-phpcgiXX .php</code>
|-
|設定ディレクトリー
| colspan="2" rowspan="1" |<code>/virtual/<username>/public_html/.fast-cgi-bin/</code>
|-
|CGIの実行ファイル
|<code>phpXX.fcgi</code>
|<code>phpXX.cgi</code>
|-
|PHPの設定ファイル
|<code>phpXX.ini</code>
|<code>php.ini</code>
|-
|設定の反映タイミング
|バージョン切替時
|即時
|}
~/public_html/.fast-cgi-bin/のphpXX.fcgi phpXX.cgiがCGIの実行ファイル。このファイルか最後の行のexecのパスを変更すると、自前コマンドに変更可能。


@/</;type=自体を送信したい場合、-Fではなく、--form-stringを指定する。
FastCGIは管理画面からバージョンを変更したタイミングで反映される。ただ、ファイル拡張子が.phpじゃないとこのFastCGIが実行されない模様。


===== curl: (60) SSL certificate problem: self-signed certificate =====
CGIは.htaccessに以下の内容を記述してCGI板PHPのバージョンを指定する。
Ref: [https://linuxfan.info/curl-insecure curlで「自己署名証明書」を受け入れるには【curl: (60) SSL certificate problem: self signed certificate】 | LFI].
AddHandler application/x-httpd-phpcgiXX .php
cgiのファイルには実行権限が必要。
chmod +x py.py
拡張子がないとダメな模様。加えて、.htaccessに以下の記述。
AddHandler cgi-script .py
これでpy.pyで動作はする。


--insecureオプションを指定すると、localhostなどでの自己署名証明書を許可する。
拡張子じゃなくてファイル名で実行したい場合、SetHandlerでしていする ([https://senooken.jp/post/2019/06/01/2333/ AddType, AddHandler, SetHandlerの違い – senooken JP])。
<FilesMatch py$>
    SetHandler cgi-script
</FilesMatch>
これでpyでもアクセスできる。


===== curl: Failed writing body =====
FastCGI版の場合、以下のような設定でファイル名でマッチさせれば実行できそうな気もするが。
[https://askubuntu.com/questions/1449492/right-after-piping-to-head-tail-curl-23-failure-writing-output-to-desti pipe - Right After piping to "head"/"tail": "curl: (23) Failure writing output to destination" - Ask Ubuntu]
<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>
500
<FilesMatch gnusocial$>
        SetHandler application/x-httpd-php
</FilesMatch>
pythonがphpとして認識され、テキストがそのまま表示される。


以下のようにhead -n 1を指定するとcurlがエラーを出力する。
SetHandler fcgid-scriptにしたらFastCGIで動作する。プログラムがFastCGI対応になっている必要がある。
  curl -H "Content-Type: application/json; charset=utf-8" -H "X-HD-apitoken:$TOKEN"        -d "{\"dbSchemaId\":$dbSchemaId, \"limit\":1, \"offset\":$offset}"        <nowiki>https://$DOMAIN/$ACCOUNT/api/csvexport/version/1.0</nowiki> | head -n 1
  <FilesMatch gnusocial$>
        SetHandler fcgid-script
</FilesMatch>


curl: Failed writing body
== Analytics ==
curlは標準出力に全部書き込めたかチェックしているようで、head -n 1で切り捨てたらcurlはエラーになる。


対策は、curl -sで出力を抑制するとのこと。これで解決。
==== Exam ====
<nowiki>##</nowiki> About


=== Wireshark ===
<nowiki>https://gnusocial.jp/notice/4506679</nowiki>


==== TLS ====
<nowiki>###</nowiki> 全般
Ref: [https://www.toyo.co.jp/onetech_blog/articles/detail/id=36994 SSL/TLSの復号#1 ~Wiresharkの設定~ | 東陽テクニカ | “はかる”技術で未来を創る | ワン・テクノロジーズ・カンパニー].


Wiresharkで通信パケットを確認する場合、デフォルトでTLSで暗号化されているので、内容がわからない。WiresharkでTLSに対応しておく必要がある。
- マーケティング・ビジネス実務検定


[Preferences]-[Protocols]-[TCP] を選ぶ。
- IMA検定


* ☑Allow subdissector to reassemble TCP stream
- Web検定
* ☑Reassemble out-of-order semgemnts


上記をチェックしておく。デフォルトでチェックされていた。
- ネットマーケティング検定


続いて、セッションごとのPre-Master Secretを登録する。
<nowiki>###</nowiki> 解析系


Chrome/Firefoxだと、環境変数SSLKEYLOGFILEを設定すれば、このファイルにTLSセッションキーを出力するので、これをWiresharkで読み込むことで、復号対応する。
- ウェブ解析士


以下のコマンド相当で、任意のファイル・場所にログファイルを指定する。
- GAIQ
export SSLKEYLOGFILE=/tmp/sslkey.log
Macだとlaunchctlで設定しておくといい。これでWebブラウザー経由の場合は見えるようになる。


=== Security ===
- 統計検定


==== DoS攻撃 ====
- Webアナリスト検定
いくつか対策方法がある。


* [https://lite.ip2location.com/ip-address-ranges-by-country?lang=ja 国別のIPアドレス範囲]
GAIQが無料だしどうせ使うからいいかな。
* [https://rakko.tools/tools/11/ IPアドレスから住所検索:国、地域の特定 | ラッコツールズ🔧]


サーバーログにIPアドレスが残るから、それで攻撃元の国を特定して、該当国を一括アクセス拒否。これが効果あるかもしれない。
<nowiki>https://wacul-ai.com/blog/access-analysis/google-analytics-method/gaiq/</nowiki>


攻撃元の国は途上国とかが多いだろうから。IPアドレスは簡単に変更できるが、国を変えるのはたいへんだろう。
<nowiki>https://www.plan-b.co.jp/blog/seo/12792/</nowiki>


==== バリデーションの実装 ====
<nowiki>##</nowiki> URL


* [https://teratail.com/questions/81861 フロント側で入力チェックをしていればサーバー側では入力チェックは必要ない?]
- <nowiki>https://ceres-inc.jp/business-tips/recommended-webmarketing-shikaku/</nowiki>
* [https://qiita.com/mi2__user/items/f2f415ccbb0a625c8647 フロントエンドの"バリデーション"は最低限の方がいいらしい。 #TypeScript - Qiita]


基本的に、バックエンドで主にチェックして、フロントエンドはUXの向上目的で実装する。データの重複チェックはDBアクセスが必要だったりするから。また、API経由などフロントがそもそもないケースもある。
- <nowiki>https://mynavi-creator.jp/blog/article/qualification-for-web-marketer</nowiki>


ただ、社内システムのような、画面経由でしか使わない。悪者がほぼいないと思われるケースは、フロントエンドでの検証だけでも十分に感じる。
- <nowiki>https://www.icloud.co.jp/article/exam/features-and-5-acquisition-benefits.html</nowiki>


==== 二重送信 ====
- <nowiki>https://digitor.jp/textbook/web-analytical-qualification/</nowiki>


* [https://www.youfit.co.jp/archives/4545 フォームの二重送信を防止する方法 - 福岡・東京のシステム開発会社 (株)ユーフィット]
=== Tool ===
* [https://qiita.com/syobochim/items/120109315f671918f28d さいきょうの二重サブミット対策 #JavaScript - Qiita]
サイト分析用のツールがいくつかある ([https://hidesunblog.com/blog-ranking-sites/ 2023年ブログランキング!おすすめブログランキングサイト比較【一般人向け】])。


submitボタンのダブルクリック、リロード、ブラウザーバック・フォワードなど、フォーム周りで注意が必要な保安要素がある。
* SimilarWeb
* Ubersuggest
* ahrefs
* Googleキーワードプランナー


# ボタン連打
=== 閲覧数取得 ===
# ブラウザーバック
出典: [https://affiliate-jpn.com/archives/5595 GoogleAnalyticsで自サイトの人気記事ランキングを表示する方法 | アフィリエイトJAPAN]。
# リロード (PRG)


項目ごとにすべき対策が異なる。
* [行動]-[サイトコンテンツ]-[全てのページ]
* [表示する行数]=5000
* [エクスポート]=TSV


===== 連打 =====
=== 流入元特定 ===
「[https://support.google.com/analytics/thread/252885536/%E4%BC%9A%E5%93%A1%E7%99%BB%E9%8C%B2%E7%94%BB%E9%9D%A2%E3%81%AE%E6%B5%81%E5%85%A5%E5%85%83%E6%8E%A2%E7%B4%A2%E6%96%B9%E6%B3%95%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6?hl=ja 会員登録画面の流入元探索方法について - Google アナリティクス コミュニティ]」どのページから会員登録があったか、会員登録に結びつく記事は非常に重要。<blockquote>こんにちは。


* [https://www.youfit.co.jp/archives/4545 フォームの二重送信を防止する方法 - 福岡・東京のシステム開発会社 (株)ユーフィット]
探索レポートでユーザーセグメントを作成する集計方法はいかがでしょうか。
* [https://qiita.com/syobochim/items/120109315f671918f28d さいきょうの二重サブミット対策 #JavaScript - Qiita]
* [https://codezine.jp/article/detail/769 JavaScriptを利用してフォームの二重送信を防止する|CodeZine(コードジン)]
* [https://blog.nisesagi.com/3150/ JavaScriptでformの2重送信を防止する | にせサギ ネットサギ体験ブログ]
* [https://yutaihara.com/archives/569 Javascriptで送信ボタン二度押しによる二重送信を防止する方法 | Yuta Ihara.com]


基本は、ボタンのsubmitのイベント内でdisabled=trueでの無効化。
・自由形式レポートを作成


似た考え方で、スプラッシュのモーダル表示もあり。これがわかりやすいかもしれない。
・セグメント作成 > ユーザーセグメント
$("form").submit(function() {
  var self = this;
  $(":submit", self).prop("disabled", true);
  setTimeout(function() {
    $(":submit", self).prop("disabled", false);
  }, 10000);
});
停止にしたら、二度通せなくなるので、タイムアウトで戻すとよい。


=== Browser ===
・条件は page_view > パラメータ page_location > 含む:会員登録画面のURL を指定


==== Chromium ====
・「会員登録画面閲覧ユーザー」などセグメント名をセットして保存


===== Extension =====
・探索レポートにセグメントを適用
Chromme系で愛用拡張機能を列挙する。


* [https://chromewebstore.google.com/detail/create-link/gcmghdmnkfdbncmnmlkkglmnnhagajbm Create Link]:
・ディメンション:セッションの参照元 / メディア、ランディング ページ + クエリ文字列


==== devtool/開発者ツール ====
・指標:セッション


===== イベントリスナー =====
ご確認よろしくお願いいたします。
[https://yuzu441.hateblo.jp/entry/2016/12/12/120000 要素に設定されているイベントを調べよう - ゆずめも]


[Elements]-[Event Listeners]-[handler]-右クリック-[Show function definition] でイベントリスナー関数の定義を確認できる。
※ページ閲覧の発生しなかったセッションはランディングページが (not set)になります。


===== イベント監視 =====
 開きっぱなしのタブから再訪問するセッションなどが該当します。ご参考までに。</blockquote>PMProでも似たような回答。<blockquote>Google Analytics 4 can track ecommerce conversions and then assign page value to posts that were a part of their conversion path for that engaged session. </blockquote>
[https://stackoverflow.com/questions/3787555/how-to-find-out-which-javascript-events-fired How to find out which JavaScript events fired? - Stack Overflow]


monitorEvent関数で監視できるらしい。他に、FirefoxのFirebugのlog eventsでも監視できるらしい。
== Server ==


==== Other ====
=== httpd ===
Apache HTTP Server


===== Windows Safari =====
==== About ====
httpdの利用可能な情報。


* [https://web.archive.org/web/20220220134447/https://jp.techcrunch.com/2012/07/27/20120725apple-safari-for-windows-ends/ Appleは静かにWindows版Safariの開発から手を引いてしまったのだろうか? | TechCrunch Japan]
https://chatgpt.com/c/6761f851-df0c-800b-86e9-1624b458d66d
* [http://web.archive.org/web/20120728130701/https://support.apple.com/kb/DL1531 Safari 5.1.7 for Windows]
# 使用可能な指令一覧
apachectl -L
httpd -L
# 使用可能なモジュール一覧
apachectl -M
httpd -M
.htaccessで使用可能な指令の一覧。


一応ある。2012-05-09のSafari 5.1.7までWindows版が提供されていた。DL1531。
[https://senooken.jp/post/2019/04/19/2010/ .htaccessで使用可能な指令一覧 – senooken JP]


=== Other ===
==== Operation ====
サーバーの稼働や状態確認などで重要な操作がいくつかある。systemd前提。


==== Tool ====
ログ・状態確認。
sudo systemctl status apache2
sudoをつけないと詳細ログを確認できない。
sudo systemctl restart apache2
sudo systemctl start apache2
sudo systemctl stop apache2


* [https://web-toolbox.dev/ Web ToolBox | 開発者向けのオンラインツール]
==== Access Control ====
* [https://tm-webtools.com/ TM - WebTools]


いくつかWeb関係の開発で役立つツール集を公開しているサイトがある。
* [https://httpd.apache.org/docs/2.4/en/howto/access.html Access Control - Apache HTTP Server Version 2.4]
* [https://httpd.apache.org/docs/2.4/en/howto/auth.html Authentication and Authorization - Apache HTTP Server Version 2.4]
* [https://httpd.apache.org/docs/2.4/ja/mod/mod_authz_core.html#logic mod_authz_core - Apache HTTP Server Version 2.4]


==== localhost ====
DoS攻撃対策などで重要な設定。


* [[wikipedia:Special-use_domain_name|Special-use domain name - Wikipedia]]
mod_authz_core/mod_authz_hostがコアモジュール。mod_rewriteも関係ある。
* [https://ja.wikipedia.org/wiki/.localhost .localhost - Wikipedia]


RFC 6761 で規定。RFC 2606<nowiki/>で予約。DNSに登録されることはないため、テスト目的で使用可能。ループバック (送信元にそのまま返す) インターフェイス。
基本構文は以下。
Require host <address>
Require ip <ip address>
1番目の形式はドメイン名。2番目はIPアドレス。部分マッチする。マッチしたもののアクセスを許可する。


IPv4=127.0.0.1/IPv6=::1とされている。
Requireの直後にnotを指定してアクセス禁止にできる。こちらが重要。


== Shared Host ==
==== mod_cgi ====
[https://httpd.apache.org/docs/current/en/mod/mod_cgi.html mod_cgi - Apache HTTP Server Version 2.4]


=== Free ===
CGIプロトコルのApacheモジュール。cgi-scriptにハンドラーを割り当てるとCGIとして扱う。
無料で使用可能な共用ホスティングサービスがある。


==== スタードメイン無料サーバー ====
==== mod_fcgid ====
ドメインをセットで利用する必要があるものの、スタードメインのスタードメイン無料サーバーがけっこういい。
[https://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html mod_fcgid - Apache HTTP Server Version 2.5]


[https://www.star-domain.jp/service/free_server.php 無料レンタルサーバー | スタードメイン - ドメイン取得 100円(税込)~]
FastCGIプロトコルのApacheモジュール。AddHandlerかSetHandlerでfcgid-scriptハンドラーに割り当てられると、FastCGIとして処理される。


jpドメインの金額が相場の中では安い方で、それに無料サーバーがついていくる点。
プログラム側もFastCGIに対応している必要がある。


* ディスク容量 20GB
==== Error ====
* DB 1GB
sudo systemctl status apache2


ただし、SSHやコマンドは使えないので、FTPでWordPressを展開して設置するとか、そういう簡単な使い方だけ。ただ、それでもWordPressでWebサイトを構築するくらいなら十分だと思う。
● apache2.service - The Apache HTTP Server
 
      Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
=== CORESERVER ===
    Drop-In: /etc/systemd/system/apache2.service.d
 
              └─privatetmp.conf
==== メール ====
      Active: failed (Result: exit-code) since Fri 2024-12-06 15:09:28 JST; 12s ago
 
        Docs: <nowiki>https://httpd.apache.org/docs/2.4/</nowiki>
* [https://www2.bwt.jp/wiki/?Custom_Filter_of_Coreserver Custom_Filter_of_Coreserver - PukiWiki]
    Process: 38461 ExecStart=/usr/sbin/apachectl start (code=exited, status=1/FAILURE)
* [https://help.coreserver.jp/manual/v2/spam-filter/ スパムフィルターの設定 | マニュアル | サポート | レンタルサーバー CORESERVER(コアサーバー)]
* [https://help.coreserver.jp/manual/v1/customfilter/ カスタムフィルターの設定 | マニュアル | サポート | レンタルサーバー CORESERVER(コアサーバー)]
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: AH00548: NameVirtualHost has no effect and will be removed in the next release /etc/apache2/ports.conf:8
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: [Fri Dec 06 15:09:28.259153 2024] [core:warn] [pid 38464] AH00117: Ignoring deprecated use of DefaultType in line 122 of /etc/apache2/apache2.conf.
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: AH00112: Warning: DocumentRoot [/home/gree/frontend/greenet/htdocs_net] does not exist
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: AH00526: Syntax error on line 7 of /etc/apache2/conf-available/rewrite-greenet.conf:
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: RewriteRule: unknown flag 'UnsafeAllow3F'
Dec 06 15:09:28 z-ken-senoo apachectl[38461]: Action 'start' failed.
Dec 06 15:09:28 z-ken-senoo apachectl[38461]: The Apache error log may have more information.
Dec 06 15:09:28 z-ken-senoo systemd[1]: apache2.service: Control process exited, code=exited, status=1/FAILURE
Dec 06 15:09:28 z-ken-senoo systemd[1]: apache2.service: Failed with result 'exit-code'.
Dec 06 15:09:28 z-ken-senoo systemd[1]: Failed to start The Apache HTTP Server.


情報
===== AH00548: NameVirtualHost has no effect and will be removed in the next release /etc/apache2/ports.conf:8 =====
NameVirtualHost指令が廃止予定なので、行を削除して対応する。


* [https://www2.bwt.jp/wiki/?CoreServer_Mail_Custom CoreServer_Mail_Custom - PukiWiki]
===== AH00117: Ignoring deprecated use of DefaultType in line 122 of /etc/apache2/apache2.conf. =====
* [https://bwt.blog.ss-blog.jp/2021-03-28 coreserverのメール設定:BWT Lab.:SSブログ]
* [https://qwerty.work/blog/2017/01/valueserver-spammail-filter-rule.php バリューサーバーのフィルター設定でスパムメール(迷惑メール)対策する方法 - QWERTY.WORK]
* [https://awmt.jp/dekirukana/archives/2253 コアサーバー V1にてカスタムフィルターで「ごみ箱」を指定したときの確認方法 – AWMTの、できるかな?]


ルールが特殊なので注意する。
* Gentooの~amd64にApache 2.4.1が来たので試してみた https://meihong.work/computer/server-administration/apache/gentoo%E3%81%AEamd64%E3%81%ABapache-2-4-1%E3%81%8C%E6%9D%A5%E3%81%9F%E3%81%AE%E3%81%A7%E8%A9%A6%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F/
* Upgrading to 2.4 from 2.2 https://httpd.apache.org/docs/2.4/upgrading.html
* DefaultType Directive https://httpd.apache.org/docs/2.4/en/mod/core.html#defaulttype


ゴミ箱に振り分ける場合。
DefaultTypeはnone以外意味がなく、警告表示になる模様。


順1 で[<code>./.Trash</code>] を指定
==== .htaccess ====


順2
===== directive =====
[https://senooken.jp/post/2019/04/19/2010/ .htaccessで使用可能な指令一覧 – senooken JP]


* 条件:  [<code>.*</code>]
.htaccessで使用不能なよく登場して誤解する指令を整理しておく。
* 処理:  <code>./</code>、に振り分ける


条件部分には正規表現が使えるように見える。
* Alias
* ScriptAlias
* Directory/DirectoryMatch
* Location/LocationMatch
逆にOKなもの。


破棄にしないといけない。転送する場合、カスタムフィルターの中に転送を入れる。条件を.*にする。
* Files/FilesMatch


カスタムフィルターにくせがある。
=== E-mail ===
[[https://www.itti.jp/web-direction/spam-blacklist-release/ サーバーIPがブラックリストに載ってメール送信エラーになるのを解除する方法]]


* エスケープ(\を前置する)が必要な文字は「'」「"」「|」「`」「~」「?」「!」
MailHog: Go言語製のメールサーバーソフト。


==== Value Domain ネットde診断 byGMO ====
=== Debian ===


* [https://www.value-domain.com/information/detail/?no=20240606-1 弊社レンタルサーバー上で運用中のドメインにおける自動セキュリティ診断開始のお知らせ | お知らせ - バリュードメイン]
==== PHP8 ====
* [https://www.value-domain.com/security/net-de-shindan/ Value Domain ネットde診断 byGMO - バリュードメイン]
[How To Install PHP 8.0 on Debian 11/10/9 | ComputingForGeeks](<nowiki>https://computingforgeeks.com/how-to-install-php-on-debian-linux/</nowiki>)


2024-06-07 Friからバリュードメイン系の利用者に無料で提供しているセキュリティー診断ツール。
Debian 11の場合、PHP 8には外部リポジトリーが必要なので追加する。


== Analytics ==
sudo apt update


==== Exam ====
sudo apt install -y lsb-release ca-certificates apt-transport-https software-properties-common gnupg2
<nowiki>##</nowiki> About


<nowiki>https://gnusocial.jp/notice/4506679</nowiki>
PHPパッケージを追加する。


<nowiki>###</nowiki> 全般
echo "deb <nowiki>https://packages.sury.org/php/</nowiki> $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/sury-php.list


- マーケティング・ビジネス実務検定
wget -qO - <nowiki>https://packages.sury.org/php/apt.gpg</nowiki> | sudo apt-key add -


- IMA検定
sudo apt update


- Web検定
これでPHP8を参照できるので、インストールする。


- ネットマーケティング検定
sudo apt install php8.2


<nowiki>###</nowiki> 解析系
[How to Switch between Multiple PHP Version on Debian 12/11/10 – TecAdmin](<nowiki>https://tecadmin.net/switch-between-multiple-php-version-on-debian/</nowiki>)


- ウェブ解析士
インストールしたら、PHPのバージョンを切り替える。


- GAIQ
a2dismod php7.4


- 統計検定
a2enmod php8.2


- Webアナリスト検定
sudo systemctl restart apache2


GAIQが無料だしどうせ使うからいいかな。
php 8.2にするとこういうエラー。


<nowiki>https://wacul-ai.com/blog/access-analysis/google-analytics-method/gaiq/</nowiki>
[Sat Sep 02 11:31:02.558029 2023] [php:error] [pid 25644] [client 133.106.38.37:57181] PHP Fatal error:  Uncaught Error: Undefined constant "DB_DATAOBJECT_ERROR_NODATA" in /var/www/gnusocial/public/index.php:104\nStack trace:\n#0 [internal function]: handleError()\n#1 {main}\n  thrown in /var/www/gnusocial/public/index.php on line 104


<nowiki>https://www.plan-b.co.jp/blog/seo/12792/</nowiki>
念のためdockerで起動を試みましたが、同じくトップ画面を開くと同じエラーになります。


<nowiki>##</nowiki> URL
<<nowiki>https://notabug.org/gnusocialjp/gnusocial/src/main/docker/development</nowiki>> にDockerでの起動方法があります。`docker compose up -d` を実行するだけでlocalhostでアクセスできます。


- <nowiki>https://ceres-inc.jp/business-tips/recommended-webmarketing-shikaku/</nowiki>
私とあなたとの環境の違いを排除したいので、dockerのインストールだけ頑張って、それでdockerでも簡単に動作確認してくれませんか?


- <nowiki>https://mynavi-creator.jp/blog/article/qualification-for-web-marketer</nowiki>
==== alternative ====
Ref: [https://wiki.debian.org/DebianAlternatives DebianAlternatives - Debian Wiki].


- <nowiki>https://www.icloud.co.jp/article/exam/features-and-5-acquisition-benefits.html</nowiki>
OS内でバージョン違いのプログラムを管理するための仕組みがある。それがupdate-alternativesコマンド。<syntaxhighlight lang="sh">
sudo update-alternatives --display vi
sudo update-alternatives --config vi
</syntaxhighlight>オプションとコマンド名を指定することで、現在の実体と更新ができる。


- <nowiki>https://digitor.jp/textbook/web-analytical-qualification/</nowiki>
=== XAMPP ===


=== Tool ===
==== ポート番号変更 ====
サイト分析用のツールがいくつかある ([https://hidesunblog.com/blog-ranking-sites/ 2023年ブログランキング!おすすめブログランキングサイト比較【一般人向け】])。
[https://qiita.com/neneta0921/items/3c2f9ac8ea9b5bcfc6e6 Xamppでポート競合を防ぐ方法 #PHP - Qiita]


* SimilarWeb
XAMPP Control PanelのConfigから変更可能。
* Ubersuggest
* ahrefs
* Googleキーワードプランナー


=== 閲覧数取得 ===
phpmyadminはConfigのphpmyadminで、Servers.portを追加する。
出典: [https://affiliate-jpn.com/archives/5595 GoogleAnalyticsで自サイトの人気記事ランキングを表示する方法 | アフィリエイトJAPAN]。


* [行動]-[サイトコンテンツ]-[全てのページ]
== Vim ==
* [表示する行数]=5000
* [エクスポート]=TSV


=== 流入元特定 ===
=== Other ===
「[https://support.google.com/analytics/thread/252885536/%E4%BC%9A%E5%93%A1%E7%99%BB%E9%8C%B2%E7%94%BB%E9%9D%A2%E3%81%AE%E6%B5%81%E5%85%A5%E5%85%83%E6%8E%A2%E7%B4%A2%E6%96%B9%E6%B3%95%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6?hl=ja 会員登録画面の流入元探索方法について - Google アナリティクス コミュニティ]」どのページから会員登録があったか、会員登録に結びつく記事は非常に重要。<blockquote>こんにちは。


探索レポートでユーザーセグメントを作成する集計方法はいかがでしょうか。
==== Async ====
https:/github.com/skywind3000/asyncrun.vim


・自由形式レポートを作成
asyncrun.vimは1個のバックグラウンド処理しか対応していない。


・セグメント作成 > ユーザーセグメント
<nowiki>https://github.com/skywind3000/asyncrun.vim/issues/12</nowiki>


・条件は page_view > パラメータ page_location > 含む:会員登録画面のURL を指定
vim-dispatchならいけるのか?


・「会員登録画面閲覧ユーザー」などセグメント名をセットして保存
==== Binary ====
[https://vim-jp.org/vim-users-jp/2010/03/21/Hack-133.html vim-jp » Hack #133: バイナリファイルを編集する]


・探索レポートにセグメントを適用
==== grep ====
非同期でgrepする方法。


・ディメンション:セッションの参照元 / メディア、ランディング ページ + クエリ文字列
<nowiki>https://superuser.com/questions/861783/how-to-run-a-grep-in-vim-asynchronously</nowiki>


・指標:セッション
<nowiki>https://www.reddit.com/r/vim/comments/5ses2e/async_grep_in_vim_8/</nowiki>


ご確認よろしくお願いいたします。
Vim 8の非同期APIはプラグイン用。


※ページ閲覧の発生しなかったセッションはランディングページが (not set)になります。
<nowiki>*</nowiki> <nowiki>https://github.com/mhinz/vim-grepper</nowiki>


 開きっぱなしのタブから再訪問するセッションなどが該当します。ご参考までに。</blockquote>PMProでも似たような回答。<blockquote>Google Analytics 4 can track ecommerce conversions and then assign page value to posts that were a part of their conversion path for that engaged session. </blockquote>
<nowiki>*</nowiki> <nowiki>https://github.com/skywind3000/asyncrun.vim</nowiki>


== Server ==
<nowiki>*</nowiki> <nowiki>https://github.com/tpope/vim-dispatch</nowiki>


=== httpd ===
<nowiki>https://wonderwall.hatenablog.com/entry/2017/10/09/210000</nowiki>
Apache HTTP Server


==== Operation ====
asyncrun.vimでやるのがよさそう。
サーバーの稼働や状態確認などで重要な操作がいくつかある。systemd前提。


ログ・状態確認。
==== AnsiEsc ====
sudo systemctl status apache2
<nowiki>*</nowiki> https:/unix.stackexchange.com/questions/444226/how-to-make-vim-interpret-escaped-characters-as-colors
sudoをつけないと詳細ログを確認できない。
sudo systemctl restart apache2
sudo systemctl start apache2
sudo systemctl stop apache2


==== Access Control ====
<nowiki>*</nowiki> https:/superuser.com/questions/358409/how-can-i-tell-vim-to-show-ansi-escape-codes-properly


* [https://httpd.apache.org/docs/2.4/en/howto/access.html Access Control - Apache HTTP Server Version 2.4]
本家は太字に対応していないのでこちらがいいかな。
* [https://httpd.apache.org/docs/2.4/en/howto/auth.html Authentication and Authorization - Apache HTTP Server Version 2.4]
* [https://httpd.apache.org/docs/2.4/ja/mod/mod_authz_core.html#logic mod_authz_core - Apache HTTP Server Version 2.4]


DoS攻撃対策などで重要な設定。
- https:/github.com/powerman/vim-plugin-AnsiEsc
 
ただし、こちらはgvimでクリック時にカーソル位置がずれる。
 
=== program ===
 
==== C ====
[https://daisuzu.hatenablog.com/entry/2012/05/06/204019 ワシのVimプラグインは百八式まであるぞ - daisuzu's notes]
 
【C/C++】


mod_authz_core/mod_authz_hostがコアモジュール。mod_rewriteも関係ある。
     87. a.vim


基本構文は以下。
        C/C++のヘッダとソースを切り替えます。
Require host <address>
Require ip <ip address>
1番目の形式はドメイン名。2番目はIPアドレス。部分マッチする。マッチしたもののアクセスを許可する。


Requireの直後にnotを指定してアクセス禁止にできる。こちらが重要。
     88. c.vim


==== Error ====
        C/C++のテンプレートやイディオムの入力をサポートしてくれます。
sudo systemctl status apache2


● apache2.service - The Apache HTTP Server
     89. CCTree
      Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
    Drop-In: /etc/systemd/system/apache2.service.d
              └─privatetmp.conf
      Active: failed (Result: exit-code) since Fri 2024-12-06 15:09:28 JST; 12s ago
        Docs: <nowiki>https://httpd.apache.org/docs/2.4/</nowiki>
    Process: 38461 ExecStart=/usr/sbin/apachectl start (code=exited, status=1/FAILURE)
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: AH00548: NameVirtualHost has no effect and will be removed in the next release /etc/apache2/ports.conf:8
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: [Fri Dec 06 15:09:28.259153 2024] [core:warn] [pid 38464] AH00117: Ignoring deprecated use of DefaultType in line 122 of /etc/apache2/apache2.conf.
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: AH00112: Warning: DocumentRoot [/home/gree/frontend/greenet/htdocs_net] does not exist
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: AH00526: Syntax error on line 7 of /etc/apache2/conf-available/rewrite-greenet.conf:
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: RewriteRule: unknown flag 'UnsafeAllow3F'
Dec 06 15:09:28 z-ken-senoo apachectl[38461]: Action 'start' failed.
Dec 06 15:09:28 z-ken-senoo apachectl[38461]: The Apache error log may have more information.
Dec 06 15:09:28 z-ken-senoo systemd[1]: apache2.service: Control process exited, code=exited, status=1/FAILURE
Dec 06 15:09:28 z-ken-senoo systemd[1]: apache2.service: Failed with result 'exit-code'.
Dec 06 15:09:28 z-ken-senoo systemd[1]: Failed to start The Apache HTTP Server.


===== AH00548: NameVirtualHost has no effect and will be removed in the next release /etc/apache2/ports.conf:8 =====
        cscopeを使って関数のコールグラフを表示してくれます。
NameVirtualHost指令が廃止予定なので、行を削除して対応する。


===== AH00117: Ignoring deprecated use of DefaultType in line 122 of /etc/apache2/apache2.conf. =====
     90. Source-Explorer-srcexpl.vim


* Gentooの~amd64にApache 2.4.1が来たので試してみた https://meihong.work/computer/server-administration/apache/gentoo%E3%81%AEamd64%E3%81%ABapache-2-4-1%E3%81%8C%E6%9D%A5%E3%81%9F%E3%81%AE%E3%81%A7%E8%A9%A6%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F/
        ソース解析ツール、Source InsightのVim版です。
* Upgrading to 2.4 from 2.2 https://httpd.apache.org/docs/2.4/upgrading.html
* DefaultType Directive https://httpd.apache.org/docs/2.4/en/mod/core.html#defaulttype


DefaultTypeはnone以外意味がなく、警告表示になる模様。
     91. trinity.vim


=== E-mail ===
        taglist, srcexpl, nerdtreeを同時に起動して
[[https://www.itti.jp/web-direction/spam-blacklist-release/ サーバーIPがブラックリストに載ってメール送信エラーになるのを解除する方法]]


MailHog: Go言語製のメールサーバーソフト。
        VimがIDE画面のような画面になります。


=== Debian ===
     92. cscope-menu


==== PHP8 ====
        cscope用のメニューを表示してくれます。
[How To Install PHP 8.0 on Debian 11/10/9 | ComputingForGeeks](<nowiki>https://computingforgeeks.com/how-to-install-php-on-debian-linux/</nowiki>)


Debian 11の場合、PHP 8には外部リポジトリーが必要なので追加する。
     93. gtags.vim


sudo apt update
        gtagsを使ってファイルを開けます。


sudo apt install -y lsb-release ca-certificates apt-transport-https software-properties-common gnupg2
     94. DoxygenToolkit.vim


PHPパッケージを追加する。
        Doxygenコメントの入力をサポートしてくれます。


echo "deb <nowiki>https://packages.sury.org/php/</nowiki> $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/sury-php.list
== Visual Studio Code ==


wget -qO - <nowiki>https://packages.sury.org/php/apt.gpg</nowiki> | sudo apt-key add -
=== Keybind ===


sudo apt update
==== 矩形選択 ====
Ref: [https://mitomito.hatenablog.jp/entry/2021/01/27/073000#:~:text=VS%20Code%E3%81%AE%E7%9F%A9%E5%BD%A2%E9%81%B8%E6%8A%9E%E3%81%A8%E7%9F%A9%E5%BD%A2%E8%B2%BC%E4%BB%98%E3%81%AE%E6%93%8D%E4%BD%9C%E6%96%B9%E6%B3%95%201%20%E3%83%9E%E3%82%A6%E3%82%B9%E3%81%A7%E6%93%8D%E4%BD%9C%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%20shift%20%2B%20alt%20%2B,shift%20%2B%20alt%20%2B%20%E7%9F%A2%E5%8D%B0%E3%81%A7%E4%BB%BB%E6%84%8F%E3%81%AE%E7%AF%84%E5%9B%B2%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%97%E3%80%81%20%28or%20%E5%88%87%E3%82%8A%E5%8F%96%E3%82%8A%29%E3%81%99%E3%82%8B%20 VS Codeの矩形選択と矩形貼付の操作方法 - mito’s blog].


これでPHP8を参照できるので、インストールする。
* s-alt-クリック
* c-s-alt-矢印
ジャンプ


sudo apt install php8.2
* 括弧ジャンプ: C-S-\


[How to Switch between Multiple PHP Version on Debian 12/11/10 – TecAdmin](<nowiki>https://tecadmin.net/switch-between-multiple-php-version-on-debian/</nowiki>)
=== Config ===


インストールしたら、PHPのバージョンを切り替える。
==== Default terminal ====
Ref: [https://stackoverflow.com/questions/44435697/change-the-default-terminal-in-visual-studio-code bash - Change the default terminal in Visual Studio Code - Stack Overflow].


a2dismod php7.4
[F1]-[Terminal: Select Default Profile]


a2enmod php8.2
=== cscope ===
cscope用のプラグインが何個かある。


sudo systemctl restart apache2
* [https://marketplace.visualstudio.com/items?itemName=xulion.codescope scope4code - Visual Studio Marketplace]
* [https://marketplace.visualstudio.com/items?itemName=SeungukShin.cscope-code cscope-code - Visual Studio Marketplace]


php 8.2にするとこういうエラー。
scope4codeのほうがいろいろできそうだが、うまく動作しなかった。使い方がよくわからない。


[Sat Sep 02 11:31:02.558029 2023] [php:error] [pid 25644] [client 133.106.38.37:57181] PHP Fatal error:  Uncaught Error: Undefined constant "DB_DATAOBJECT_ERROR_NODATA" in /var/www/gnusocial/public/index.php:104\nStack trace:\n#0 [internal function]: handleError()\n#1 {main}\n  thrown in /var/www/gnusocial/public/index.php on line 104
cscope-codeはシンプルだが動作した。こちらを当分使うことにする。


念のためdockerで起動を試みましたが、同じくトップ画面を開くと同じエラーになります。
Macの場合、control-. sのように、control-.の後に、controlを話してsを押すと発動する。カーソル下のシンボルしか使えない感じなのがネック。まあいい。


<<nowiki>https://notabug.org/gnusocialjp/gnusocial/src/main/docker/development</nowiki>> にDockerでの起動方法があります。`docker compose up -d` を実行するだけでlocalhostでアクセスできます。
=== Vim ===


私とあなたとの環境の違いを排除したいので、dockerのインストールだけ頑張って、それでdockerでも簡単に動作確認してくれませんか?
* [https://marketplace.visualstudio.com/items?itemName=vscodevim.vim Vim - Visual Studio Marketplace]


==== alternative ====
VSCodedでVimのキー操作を使うためのプラグイン。これが一番人気。いや、Vimのエミューレーターは中途半端な感じだから使わないほうがいいかな。
Ref: [https://wiki.debian.org/DebianAlternatives DebianAlternatives - Debian Wiki].


OS内でバージョン違いのプログラムを管理するための仕組みがある。それがupdate-alternativesコマンド。<syntaxhighlight lang="sh">
=== Extension ===
sudo update-alternatives --display vi
CSS
sudo update-alternatives --config vi
</syntaxhighlight>オプションとコマンド名を指定することで、現在の実体と更新ができる。


=== XAMPP ===
Tailwind CSS IntelliSense


==== ポート番号変更 ====
==== PHP ====
[https://qiita.com/neneta0921/items/3c2f9ac8ea9b5bcfc6e6 Xamppでポート競合を防ぐ方法 #PHP - Qiita]
Laravel Blade Snippets


XAMPP Control PanelのConfigから変更可能。
===== PHP Intelephense =====
Ref: [https://marketplace.visualstudio.com/items?itemName=bmewburn.vscode-intelephense-client PHP Intelephense - Visual Studio Marketplace].


phpmyadminはConfigのphpmyadminで、Servers.portを追加する。
VSCodeのPHPの補完拡張として人気が高い。


== Vim ==
====== Quick Start ======
設置後、しておくべき設定がある。


=== Other ===
* Go to <code>Extensions</code>.
* Search for <code>@builtin php</code>
* Disable <code>PHP Language Features</code>. Leave <code>PHP Language Basics</code> enabled for syntax highlighting.


==== Async ====
VSCodeの [PHP Language Features] を無効にしておくとのこと。
https:/github.com/skywind3000/asyncrun.vim


asyncrun.vimは1個のバックグラウンド処理しか対応していない。
後は、.php以外の拡張子でPHPファイルがあれば、関連付けを追加するとか。


<nowiki>https://github.com/skywind3000/asyncrun.vim/issues/12</nowiki>
====== Module ======
peclなどPHPの標準モジュールで一部認識できないものがある。


vim-dispatchならいけるのか?
「[https://stackoverflow.com/questions/62258598/undefined-type-imagick-in-vscodes-intelephense php - Undefined type 'Imagick' in VSCode's intelephense - Stack Overflow]」にあるように、そういう場合は [Settings]-[Stubs] で追加するとよい。


==== Binary ====
====== Coding ======
[https://vim-jp.org/vim-users-jp/2010/03/21/Hack-133.html vim-jp » Hack #133: バイナリファイルを編集する]
Ref: [https://beyondjapan.com/blog/2020/02/intelephense-vscode-php/ VSCode で PHP 開発するならインテリセンス最強の intelephense を使おう | 株式会社ビヨンド].


==== grep ====
intelephenseでコード補完を認識しやすい書き方というのがある。
非同期でgrepする方法。


<nowiki>https://superuser.com/questions/861783/how-to-run-a-grep-in-vim-asynchronously</nowiki>
まず、型をつけられるものはつける。<syntaxhighlight lang="php">
function superMethod()
{
    /** @var AwesomeService $awesomeService */
    $awesomeService = $this->app->make(AwesomeService::class);
    $awesomeService->awesomeMethod();
}
</syntaxhighlight>ローカル変数も型名を指定する。これをしないと、インスタンスでコード補完が効かない。


<nowiki>https://www.reddit.com/r/vim/comments/5ses2e/async_grep_in_vim_8/</nowiki>
=== Other ===


Vim 8の非同期APIはプラグイン用。
==== Remote ====
[https://www.mathkuro.com/vs-code/upload-and-download-remote-file/ 【WinSCPはもう不要?】VS Codeのダウンロード/アップロード機能が便利すぎる!! | マスクロドットコム]


<nowiki>*</nowiki> <nowiki>https://github.com/mhinz/vim-grepper</nowiki>
[https://code.visualstudio.com/docs/remote/remote-overview Visual Studio Code Remote Development]


<nowiki>*</nowiki> <nowiki>https://github.com/skywind3000/asyncrun.vim</nowiki>
公式拡張機能のVS Code Remote Developmentを使うと、リモートファイルをVS Codeで開いて、ドラッグドロップでファイル送受信ができるらしい。


<nowiki>*</nowiki> <nowiki>https://github.com/tpope/vim-dispatch</nowiki>
== PhpStorm ==


<nowiki>https://wonderwall.hatenablog.com/entry/2017/10/09/210000</nowiki>
=== Encoding ===


asyncrun.vimでやるのがよさそう。
* [https://pleiades.io/help/phpstorm/encoding.html エンコード | PhpStorm ドキュメント]
* [https://pleiades.io/help/phpstorm/settings-file-encodings.html ファイルエンコーディング | PhpStorm ドキュメント]


==== AnsiEsc ====
パス単位で文字エンコーディングを設定可能。
<nowiki>*</nowiki> https:/unix.stackexchange.com/questions/444226/how-to-make-vim-interpret-escaped-characters-as-colors


<nowiki>*</nowiki> https:/superuser.com/questions/358409/how-can-i-tell-vim-to-show-ansi-escape-codes-properly
[PhpStorm]-[Settings]-[Editor]-[File Encodings] から行う。


本家は太字に対応していないのでこちらがいいかな。
=== Scratch ===
[https://qiita.com/endam/items/cc2c4c2aee8d382acd9e 【New Year Calendar】君はPhpStormのScratch機能を知っているか #NewYearCalendar - Qiita]


- https:/github.com/powerman/vim-plugin-AnsiEsc
メモなどの一時ファイルの作成機能。


ただし、こちらはgvimでクリック時にカーソル位置がずれる。
[File]-[New Scratch File] からファイル形式を選んで作る。困ったらMarkdownで良いだろう。


=== program ===
作成したScratchファイルは [Project]-[Scratches and Consoles]-[Scratches] に格納される。


==== C ====
=== 矩形選択 ===
[https://daisuzu.hatenablog.com/entry/2012/05/06/204019 ワシのVimプラグインは百八式まであるぞ - daisuzu's notes]
[https://pleiades.io/help/phpstorm/multicursor.html#find-and-select-multiple-occurrences-of-a-string 複数のカーソルと選択範囲 | PhpStorm ドキュメント]


【C/C++】
方法がいくつかある。


     87. a.vim
* Cmd-Shift-8
* Option-Shift-Middle


        C/C++のヘッダとソースを切り替えます。
=== Git ===


     88. c.vim
==== Gitツールウィンドウ ====
C-9か左下のGitマークを選ぶとGitツールウィンドウの表示になる。ブランチとコミットログが表示される。ここから右クリックを使ってブランチ間の比較などができたりする。


        C/C++のテンプレートやイディオムの入力をサポートしてくれます。
==== ブランチ比較 ====


     89. CCTree
* [https://tech-blog.rakus.co.jp/entry/2017/09/14/112033 PhpStormで始めるGit生活 - RAKUS Developers Blog | ラクス エンジニアブログ]
* [https://pleiades.io/help/phpstorm/manage-branches.html#compare_branches Git ブランチの管理 | PhpStorm ドキュメント]


        cscopeを使って関数のコールグラフを表示してくれます。
コードレビューなどでよく使うブランチ同士の比較。


     90. Source-Explorer-srcexpl.vim
まず現在ブランチを比較対象ブランチに変更しておく。


        ソース解析ツール、Source InsightのVim版です。
[Git]-[Branches]-比較対象ブランチ-[Compare with]


     91. trinity.vim
これで上下に画面分割して、それぞれのブランチで固有のコミットログの一覧が表示される。派生元と派生先があるならば、片方が空になる。違うブランチ同士のマージ用に、こういう作りになっていると思われる。


        taglist, srcexpl, nerdtreeを同時に起動して
差分ファイル一覧を見るには、右側の変更ファイルペーンでC-aを選ぶ。変更のある全ファイルのリストが表示される。


        VimがIDE画面のような画面になります。
他に、Gitツールウィンドウを開いて、コミットログで右クリック-[Compare with Local]を選ぶとローカルと対象コミットとの比較になる。これがわかりやすい。


     92. cscope-menu
ただ、基本は現在ブランチか、現在のワーキングツリーとの比較になる。現在ブランチを変更しておくのが基本になる。そこだけ押さえておけば、まあなんとか使えそう。


        cscope用のメニューを表示してくれます。
=== Other ===


     93. gtags.vim
==== Window ====
[https://pleiades.io/help/phpstorm/open-close-and-move-projects.html プロジェクトを開く、移動、閉じる | PhpStorm ドキュメント]


        gtagsを使ってファイルを開けます。
ペーンを分離したり移動したりできる。


     94. DoxygenToolkit.vim
ペーン右上[…]-[View Mode]-[Window] を選ぶと、別画面に分離できる。並列時に重宝する。


        Doxygenコメントの入力をサポートしてくれます。
== PIM ==
[https://ja.wikipedia.org/wiki/Personal_Information_Manager Personal Information Manager - Wikipedia]


== Visual Studio Code ==
PIMという個人情報管理用アプリの分類がある。


=== Keybind ===
* カレンダー
* アドレス帳
* 電子メール
* タスク管理
* メモ帳
* 音声メモ
* 電卓
* 時計
* 電子辞書


==== 矩形選択 ====
=== E-mail ===
Ref: [https://mitomito.hatenablog.jp/entry/2021/01/27/073000#:~:text=VS%20Code%E3%81%AE%E7%9F%A9%E5%BD%A2%E9%81%B8%E6%8A%9E%E3%81%A8%E7%9F%A9%E5%BD%A2%E8%B2%BC%E4%BB%98%E3%81%AE%E6%93%8D%E4%BD%9C%E6%96%B9%E6%B3%95%201%20%E3%83%9E%E3%82%A6%E3%82%B9%E3%81%A7%E6%93%8D%E4%BD%9C%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%20shift%20%2B%20alt%20%2B,shift%20%2B%20alt%20%2B%20%E7%9F%A2%E5%8D%B0%E3%81%A7%E4%BB%BB%E6%84%8F%E3%81%AE%E7%AF%84%E5%9B%B2%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%97%E3%80%81%20%28or%20%E5%88%87%E3%82%8A%E5%8F%96%E3%82%8A%29%E3%81%99%E3%82%8B%20 VS Codeの矩形選択と矩形貼付の操作方法 - mito’s blog].


* s-alt-クリック
==== General ====
* c-s-alt-矢印
ジャンプ
 
* 括弧ジャンプ: C-S-\
 
=== Config ===
 
==== Default terminal ====
Ref: [https://stackoverflow.com/questions/44435697/change-the-default-terminal-in-visual-studio-code bash - Change the default terminal in Visual Studio Code - Stack Overflow].
 
[F1]-[Terminal: Select Default Profile]
 
=== cscope ===
cscope用のプラグインが何個かある。
 
* [https://marketplace.visualstudio.com/items?itemName=xulion.codescope scope4code - Visual Studio Marketplace]
* [https://marketplace.visualstudio.com/items?itemName=SeungukShin.cscope-code cscope-code - Visual Studio Marketplace]
 
scope4codeのほうがいろいろできそうだが、うまく動作しなかった。使い方がよくわからない。
 
cscope-codeはシンプルだが動作した。こちらを当分使うことにする。
 
Macの場合、control-. sのように、control-.の後に、controlを話してsを押すと発動する。カーソル下のシンボルしか使えない感じなのがネック。まあいい。
 
=== Vim ===
 
* [https://marketplace.visualstudio.com/items?itemName=vscodevim.vim Vim - Visual Studio Marketplace]
 
VSCodedでVimのキー操作を使うためのプラグイン。これが一番人気。いや、Vimのエミューレーターは中途半端な感じだから使わないほうがいいかな。
 
=== Extension ===
CSS
 
Tailwind CSS IntelliSense
 
==== PHP ====
Laravel Blade Snippets
 
===== PHP Intelephense =====
Ref: [https://marketplace.visualstudio.com/items?itemName=bmewburn.vscode-intelephense-client PHP Intelephense - Visual Studio Marketplace].
 
VSCodeのPHPの補完拡張として人気が高い。
 
====== Quick Start ======
設置後、しておくべき設定がある。
 
* Go to <code>Extensions</code>.
* Search for <code>@builtin php</code>
* Disable <code>PHP Language Features</code>. Leave <code>PHP Language Basics</code> enabled for syntax highlighting.
 
VSCodeの [PHP Language Features] を無効にしておくとのこと。
 
後は、.php以外の拡張子でPHPファイルがあれば、関連付けを追加するとか。
 
====== Module ======
peclなどPHPの標準モジュールで一部認識できないものがある。
 
「[https://stackoverflow.com/questions/62258598/undefined-type-imagick-in-vscodes-intelephense php - Undefined type 'Imagick' in VSCode's intelephense - Stack Overflow]」にあるように、そういう場合は [Settings]-[Stubs] で追加するとよい。
 
====== Coding ======
Ref: [https://beyondjapan.com/blog/2020/02/intelephense-vscode-php/ VSCode で PHP 開発するならインテリセンス最強の intelephense を使おう | 株式会社ビヨンド].
 
intelephenseでコード補完を認識しやすい書き方というのがある。
 
まず、型をつけられるものはつける。<syntaxhighlight lang="php">
function superMethod()
{
    /** @var AwesomeService $awesomeService */
    $awesomeService = $this->app->make(AwesomeService::class);
    $awesomeService->awesomeMethod();
}
</syntaxhighlight>ローカル変数も型名を指定する。これをしないと、インスタンスでコード補完が効かない。
 
== PhpStorm ==
 
=== Encoding ===
 
* [https://pleiades.io/help/phpstorm/encoding.html エンコード | PhpStorm ドキュメント]
* [https://pleiades.io/help/phpstorm/settings-file-encodings.html ファイルエンコーディング | PhpStorm ドキュメント]
 
パス単位で文字エンコーディングを設定可能。
 
[PhpStorm]-[Settings]-[Editor]-[File Encodings] から行う。
 
== PIM ==
[https://ja.wikipedia.org/wiki/Personal_Information_Manager Personal Information Manager - Wikipedia]
 
PIMという個人情報管理用アプリの分類がある。
 
* カレンダー
* アドレス帳
* 電子メール
* タスク管理
* メモ帳
* 音声メモ
* 電卓
* 時計
* 電子辞書


=== E-mail ===
===== winmail.dat =====
[https://winmaildat.net/ winmail.dat変換ツール(インストール不要)]


==== General ====
MS outlookなどで使われる添付ファイルの形式。


===== Naming =====
===== Naming =====

2025年1月22日 (水) 09:34時点における最新版

ソフトウェア開発作業全般

Other

ASCIIFlow: 画面構成図などの作成でテキストなので便利かもしれない。

Project

名簿付きの寄付

  • Vim: https://vim-jp.org/vimdoc-ja/sponsor.html
  • Vim (list): https://www.vim.org/sponsor/hall_of_honour.php
  • KDE: https://relate.kde.org/
  • KDE (list): https://relate.kde.org/civicrm/profile?gid=18&search=0
  • Conservancy (list): https://sfconservancy.org/sponsors/
  • Conservancy: https://sfconservancy.org/donate/

Kanboard

クローズ時に自動移動

[Configure project]-[Automatic actions]

  • action=[Move the task to another project]
  • Event name=Closing a task
  • Column=Done
  • Project=

これでDoneをclose時にアーカイブ用のプロジェクトに移動できる。

Communication

Skype

すべてのエモーティコンのリストはありますか? - Microsoft サポート

Skyepで使用可能な絵文字の一覧。

Slack

チャンネル

https://slack.com/intl/ja-jp/help/articles/205239967-%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB%E3%81%AB%E5%8F%82%E5%8A%A0%E3%81%99%E3%82%8B

一覧表示

[ホーム]-[チャンネル]-[管理する]-[チャンネル一覧] でチャンネル一覧を閲覧可能。

Confluence

ページの中で、 [作成] を選んでページを作ると、階層が勝手にできて、子ページへのリンクもできる。

ショートカットキー

キーボード ショートカット

https://ja.confluence.atlassian.com/doc/keyboard-shortcuts-139456.html

エディタ

ブロック フォーマット

Windows 操作 Mac
Ctrl + 0 Paragraph ⌘+ 0
Ctrl+ (1 ~ 6) (選択した番号の)見出しレベル ⌘+ (1—6)
Ctrl + 7 Preformatted ⌘+ 7
Ctrl + 8 Quote ⌘+ 8
Ctrl + Shift + B、または

* + Space

箇条書きリストを追加 ⌘ + Shift + B、または

* + Space

Ctrl + Shift + N、または

# + space

番号付きリストを追加 ⌘ + Shift + N、または

# + space

Ctrl + Shift + S Strikethrough ⌘ + Shift + S
Ctrl + Shift + Subscript ⌘ + Shift + ,
Ctrl + Shift + Superscript ⌘ + Shift + .
Ctrl + Shift + M Monospace ⌘ + Shift + M
Ctrl + \ Clear formatting ⌘ + \

豊富なフォーマット

CTRL + Shift + V

サファリのみ:Ctrl + Shift + Alt + V

書式設定なしでテキストを貼り付け ⌘ + Shift + V

Safari のみ:⌘ + Shift + Option + V

Ctrl+M Files and images ⌘+ M
Ctrl+K リンク([リンクの挿入] ダイアログが開く) ⌘ + K
Ctrl + Shift + D マークアップを挿入([マークアップの挿入] ダイアログが開く) ⌘ + Shift + D
Ctrl+Shift+A マクロ([マクロの選択] ダイアログが開く) ⌘ + Shift + A
Ctrl + Shift + O 次のインライン コメントに切り替え ⌘ + Shift + O
Ctrl + Shift + L 前のインライン コメントに切り替え ⌘ + Shift + L
CTRL + Shift + Z インライン コメントを閉じる ⌘ + Shift + Z
Ctrl + Shift + I ⌘ + Shift + I
Alt + 上矢印 行を上に挿入 Alt + 上矢印
Alt + 下矢印 下に行を挿入 Alt + 下矢印
Ctrl + Shift + X 行を切り取り ⌘ + Shift + X
Ctrl + Shift + C 行をコピー ⌘ + Shift + C
Ctrl + Shift + Y 行を上に貼り付け ⌘ + Shift + Y
Ctrl + Shift + ; 絵文字メニュー ⌘ + Shift + ;
CTRL + Shift + V 書式設定なしで貼り付け ⌘ + Shift + V
書式設定なしで貼り付け (Safari) ⌘ + Shift + Option + V
オートコンプリート

[] が勝手にリンクになるのが困る。

リンク、ファイル、マクロ、メンション、絵文字のオートコンプリート

https://ja.confluence.atlassian.com/doc/autocomplete-for-links-files-macros-mentions-and-emojis-249858190.html

オートコンプリートの無効化方法。

プロフィール画像を選択-[設定]-[エディター]-[☑️オートコンプリートの無効化]

ただ、オートコンプリートの丸ごと無効化は、便利な機能がなくなるので不味い。

一時的に回避したい場合、[の直前に何か文字があれば解釈されない。スペース開けて[があるとオートコンプリート扱いになる。


書式なしペースト

Confluenceで書式なしペースト(Ctrl+Shift+V)を有効にする #Confluence - Qiita [?]-[キーボードショートカット]-[General]-[▫️Enable General Shortcuts] にしてオフにすると有効になる。 [表の上部にペースト] と競合していたらしい。

マクロ

マクロ | Confluence Data Center 9.2 | アトラシアン製品ドキュメント

いくつか有用なマクロがある。

Other

パーマリンク

The Differences Between Various URL Formats for a Confluence Page | Confluence | Atlassian Documentation

Confluenceのページ新規作成時、パーマリンクが自動生成される。規則がある。

以下の条件にマッチしたら、padeId URLになる。それ以外は、タイトル名のURLになる。

  • [% & ? / ¥ ; " + :] などのようなURLの予約文字。
  • 非ラテン文字。
  • ページタイトル末尾が英数字以外の場合。
ページ履歴

ページ右上のメニュー-[ページ履歴]から履歴を確認できる。差分も確認できる。

ページ移動

ページの移動と順序の変更 | Confluence Data Center 9.2 | アトラシアン製品ドキュメント

ページ右上のメニュー-[移動]

Tool

General

Call tree

kcachegrindだったかな。

kscopeもこれか。

Doxygen+GraphVizで関数コールグラフ

kscope

https:/github.com/ivan0124/Linux-programming/wiki/How-to-use-KScope-to-trace-code

https:/sourceforge.net/projects/kscope/

http:/www.lemis.com/grog/software/kscope.php

cscope

cbrowser/kbrowserというGUIもある。

cscopeの大文字小文字無視検索

http://vim.1045645.n5.nabble.com/how-to-search-with-cscope-ignoring-case-td5715043.html

DBを別にする必要がありそう。

expect

端末の手動操作を自動化するソフト。

* ^と$は使えない。代わりに、\nを使う。

* 文字列の囲みに一重引用符 (') は使えない。二重引用符 (") のみ有効。

* expect文はawkみたいな感じ。

* ただし、expectは注意が必要。最初のexpectにマッチしないと先に進めない。タイムアウトとかするしかない。

expect -c "set timeout 5; spawn cat cat.txt; expect \nFAIL {send pwd/n; expect :; exit}"

https:/linuxjm.osdn.jp/html/expect/man1/expect.1.html

```

sh -eux <<-"EOT"

expect -c "set timeout 5; spawn ssh senooken@senooken-linux; expect :; send ieneko/n; expect aho {send echo aho} +x {send pwd/n}; expect /$; exit"

expect -c "set timeout 5; spawn ssh senooken@senooken-linux; expect :; send ieneko/n; expect + {send pwd/n}; expect /$; exit"

expect -c "set timeout 5; spawn cat cat.txt; expect \nFAIL {send pwd/n; expect :; exit}"

expect -c 'set timeout 10; spawn cat cat.txt; expect "aa F" {set AAA "abc"}; expect FAIL {send "$AAA/n"; expect " "; exit}'

EOT

```

GNU screen

GNU Screenコマンドをつかってみる #screen - Qiita

screenコマンド実行後に、C-a押下後に対応するキーを押して各種操作を実行する。

キー操作以外に、コマンドも用意されている。C-a :でコマンドラインモードに入る。

特に重要な操作。

  • Help
    • C-a ?
    • Command:help
  • Window
    • C-a c/C-a C/Command:screen=Windowを生成。
    • C-a space/C-a n/C-a C-n/Command:next=次のWindowへ移動。
    • C-a p/C-a C-p/C-a C-h/C-a Backspace/Command:prev=前のWindowへ移動。
  • 画面分割: Regionを分割してそこにWindowを割り当てる。
    • C-a S=横分割
    • C-a |=縦分割
    • C-a TAB/Command:focus=分割画面の移動。
  • クローズ
    • C-a X/Command:remove=現在のRegionを終了。
    • C-a Q/Command:Only=現在以外のRegionを終了。
.screenrc
スタートアップメッセージ
startup_message off
スクロール

linux screen中にマウスホイールでスクロールする方法 - 技術メモ集

デフォルトだとマウススクロールなどに対応していない。以下の設定で対応でき、通常使用で問題なくなる。

termcapinfo xterm* ti@:te@
defscrollback 100000

Binary

.so

ソフトウェアの依存関係などの調査で.soファイルの分析を行うことがある。

.soファイルの中のシンボル探し

  • nm
  • ldd
  • string

Diff

差分確認ツール。コードレビューなどで重要。

About

Macが鬼門。

M1 Macで使用可能なものの選択肢が極端に狭い。

https://chatgpt.com/c/678e249e-84f0-800b-b8da-7385d9aaf819

name OS Free GUI directory image comment
FileMerge Mac x x x Xcode付属ツール。悪くない。が、Mac専用。
P4Merge x x x - x ディレクトリー比較ができないのが惜しい。
DiffMerge x x x x - 悪くない。が開発停止。MacはIntel版のみ。
WinMerge Windows x x x 使いやすい。
Meld Windows/Linux x x x Linux系の標準。悪くない。
kdiff3 Windows/Linux x x x 開発停止。使えなくはない。
vimdiff x x x x - 使いにくい。
Visual Studio Code x x x x x ディレクトリー比較は [Compare Folders - Visual Studio Marketplace] 拡張機能。 画像比較は [Image Preview] らしい。
Intellij IDARE x - x x x
Beyond Compare x - x x x
DiffImg Windows/Linux x x x
PerceptuallDiff x - x
PixelCompare x x

DiffMerge一択になる。ファイルサイズも小さい。大きくても11 MB。

Visual Studio Codeが汎用的だから、こちらでいいかもしれない。

DiffMerge

mac で WinMerge |東京 AI 研究所

FileMerge

Mac純正のファイル差分確認ツール「FileMerge」が使いやすい - Reasonable Code

[/Applications/Xcode.app]-右クリック-[Show content]-[Contents/Applications/FileMerge.app]

コマンドラインからだとopendiff。

Coding

タイムゾーン

タイムゾーン呪いの書 #timezone - Qiita

3文字形式は避けたほうが無難。

タイムゾーン名で判定する実装があるので、UTC-9なども避けたほうがいい。

tz databaseのAsia/Tokyoなどの確実性が高い。

Regular Expression

正規表現。重要。覚えにくいが重要なものをメモしておく。

後ろからマッチ。cが置換対象。

Case

/[^c]*$/: cより右端

マッチの前後の挿入

https:/vim.fandom.com/wiki/Power_of_g

:g/GST_.*("/s/^/LOG(INFO) << "DEBUG";/r/

行頭・行末で引っ掛ける。

関数にログ
:%s/([^")]*)/) /([a-z]* /)*{/&/rLOG(INFO) << "/1";/r/g

考慮するケース

double currentTime() const override { return m_element->currentTime(); }

glob

重要。正規表現とは似ているが異なる、パターンマッチング記法 (Pattern Matching Notation)。主に、globで採用されており、ディレクトリー・ファイルのマッチングで使われる。

使用可能な記号は以下3個。以下の3文字は\でエスケープできる。

  • ?: 任意の1文字にマッチ。
  • *: 任意の0以上の文字にマッチ。
  • [: []内の1文字にマッチ。正規表現の各括弧と同じ。ただし、先頭の否定が^ではなく、!。

ファイル名マッチ時には、追加で特殊なルールがある。

.から始まるファイル名へのマッチには、.が必要。つまり、*?は先頭の.にはマッチしない。[!a] のような否定形の各括弧記法も.にはマッチしない。加えて、先頭の[.]もマッチするかは不定(unspecified)。

globで.ファイルを含めたい場合、工夫が必要 (PHP: glob - Manual)。

.[!.]* *

上記のように.ファイルのマッチとそれ以外を指定する必要がある。

.[!.]* は、...以外の..始まりのファイルにマッチする。

.*を指定すると、./..がマッチするので注意する。最近のシェルは、シェル側で気を利かせているようで、.*だと. /..はマッチしない。

引用符のネスト

シェルやプログラミング言語で、文字列リテラルの表現などで、一重引用符'と二重引用符"を使う。

JSON作成や変数展開などで、これらをネストさせたいことがある。その基本的な考え方を整理する。

交互にしていい場合は簡単二重。引用符内に一重引用符を配置、一重引用符内に二重引用符を配置すればいい。

問題はこれがNGな場合。特にありがちなのが、JSONの生成。JSONの引用符は二重引用符のみ。一重引用符の中だと、二重引用符の変数展開が使用不能。外側を二重引用符にする必要がある。

二重引用符は、内部で変数展開が可能。この都合で、バックスラッシュ\によるエスケープが有効。

基本的な方法。

  1. 既存の一重/二重引用符などをバックスラッシュでエスケープ。
  2. 全体を一重/二重引用符で囲む。

何かAwkの本か何かで、基本的な考え方の説明の記載があった気がする。

[{"ke\y":"valu\e"}] を例として考える。

  1. {"ke\y":"valu\e"}
  2. エスケープ: {\"ke\\y\":\"valu\\e\"}
  3. 全体囲み: "{\"ke\\y\":\"valu\\e\"}"

これでOK。また何か考慮不足があればそのときに考える。

ただ、元データに修正が必要なので、そのまま行きたい。ヒアドキュメント的なものが使えるならそれを使うのがいい。

例えば、シェルなら、catコマンドとコマンド置換で生テキストを使える。

echo $(cat <<-'EOT'
{"ke\y":"valu\e"}
EOT
)

.envなどで使える技?いや使えない。.envではシンプルなコマンドしか使えず、ヒアドキュメントは使えない模様。

JSONのvalue部分に適用したい場合。データの二重引用符をバックスラッシュでエスケープする。これはこうするしかない。JSONが二重引用符しか認めないから。

基本的な考え方がある。

  1. JSON value用に二重引用符"を\"で置換。
  2. \"がPHP/JavaScriptで二重引用符に扱いにならないように、\を\\に置換。
  3. JSON項目の二重引用符"を\"で置換。
  4. 全体を二重引用符"で囲む。

こういう感じ。JSONはawkでも任意の最終データで考える。途中にプログラミング言語でのパースがあるので、それを考慮する必要がある。

ケース変換

javascript - camelCase to kebab-case - Stack Overflow

キャメルケースをチェインケースにしたり、逆にしたりなどケース変換したいことがある。正規表現を駆使して実現する。

encode

【PHP入門】URLエンコードする方法(urlencode) | 侍エンジニアブログ

日本語や記号を他のコードに変換 (エンコード) する方式が何通りかある。把握しておくと役立つ。

  • パーセントエンコーディング/URLエンコード: URLで使用不能な文字を%16進数で連結。
  • UTF-8
  • base64: 全データを「A-Z」「a-z」「0-9」「+」「/」の64文字で表現。文末に=を使うので実質は65文字。
  • HTMLエンコード: HTMLで特殊な意味を持つ文字を&lt;などに変換する。

Percent-encoding

unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"

上記文字はエンコードの対象外。

英数変換

string - PHP How to encode all characters with rawurlencode - Stack Overflow

変数名への変換などで、日本語や記号を英数字 [0-9a-zA-Z] に変換したいことがある。

こういう目的だと%エンコーディングが適している。

ただし、一部の記号を許可しているので、自前で変換する。

function encode_all($str) {
    $hex = unpack('H*', $str);
    return preg_replace('~..~', '%$0', strtoupper($hex[1]));
}

$str = 'big ƒüßchen';
print_r(encode_all($str));

Term

紛らわしい用語がある。

フレームワークの中にライブラリーも含めていいと思う。

Pythonのモジュールとパッケージとライブラリとフレームワークの違い」がわかりやすい。

フレームワークはライブラリーを含んでいる。ライブラリーで共通でいいと思う。

Category

ソフトウェア開発工程 - Wikipedia

ソフトウェアの分類、ページ分類時に役立つ。

  • 言語
  • ツール: 静的解析、テスト、文書など。
  • フレームワーク

MediaWikiのページ名は全体で固有が条件なので、言語名+分類名でページを作るといい。

  • PHP language
  • PHP tool
  • PHP framework

成功時連続継続処理

一度の取得件数の上限が決まっていて、終了・失敗するまで取得を継続したいという処理がそれなりに発生する。

  1. 処理実行。
  2. 成功ならA、失敗なら終了。
  3. 処理実行。
  4. 成功ならA、失敗なら終了。

こういうパターン。いくつか実装方法があるが、while (true) のパターンが重複がなくてベストだと思う。

        /*
        // 無限ループで終了条件でブレイク
        while (true) {
            // 処理実行
            if (失敗) {
                break;
            }
            成功時処理
        }
        
        // do while
        do {
            処理実行
            if (成功時) {}            
        } while ();

        // for (初期化; 継続判定・終了判定; 成功時式) {
            処理実行
        }
        */

do-whileは成功・終了判定を2回書く必要がある。

forだと成功処理を式でしか書けない。成功処理を関数や即時実行関数式などで書くなら悪くはないし、ベストになりえる。

いや、成功時処理内の処理の結果次第で反復の終了条件などが追加で入るならNGになる。なので、やっぱりwhile(true)が無難。コード行数もそんなに変わらない。

これにさらに初回だけ、ヘッダーの取得、書き込み処理などが発生する場合、初回だけループの外でやるのがきれいだろうか?初回処理が2回登場することになるけれど。

offsetなどで初回の判定が反復内でできるから、それで分けるのがいいか?

        $offset = 0;
        while (true) {
            $currentReturnCode = $service->sendRequest(Raku2Config::API_TYPE_CSV_EXPORT, Raku2Config::CONFIG_API_URL_MULTI_API, [
                json_encode([
                    'dbSchemaId' => $table_info['dbSchemaId'],
                    'offset' => $offset,
                    'limit' => $limit,
                ])
            ]);

            $response = $service->getApiResultJson();
            // 終了条件: 戻り値が成功以外、か応答本体が1行 (ヘッダーのみ) の時。
            if (($currentReturnCode !== Raku2Config::EXIT_SUCCESS) || (substr_count($response, "\n") <= 1)) break;

            // 2回目からはヘッダー除去して書き込み。
            $start = strpos($response, "\n") + 1;
            $flat = FILE_APPEND;
            if ($offset === 0) {
                $start = $flag = 0;
                $path = stream_get_meta_data($fp = tmpfile())['uri'];
            }
            file_put_contents($path, substr($response, $start), $flag);
            $offset += $limit;
            sleep(3);
        }
        for ($offset = 0;
            ($currentReturnCode === Raku2Config::EXIT_SUCCESS) && (substr_count($response, "\n") > 1);
            (function() use (&$offset, $limit, $response) {
                // 2回目からはヘッダー除去して書き込み。
                $start = strpos($response, "\n") + 1;
                $flag = FILE_APPEND;
                if ($offset === 0) {
                    $start = $flag = 0;
                    $path = stream_get_meta_data($fp = tmpfile())['uri'];
                }
                file_put_contents($path, substr($response, $start), $flag);
                $offset += $limit;
                sleep(3);
            })()
        ) {
            $currentReturnCode = $service->sendRequest(Raku2Config::API_TYPE_CSV_EXPORT, Raku2Config::CONFIG_API_URL_MULTI_API, [
                json_encode([
                    'dbSchemaId' => $table_info['dbSchemaId'],
                    'offset' => $offset,
                    'limit' => $limit,
                ])
            ]);
            $response = $service->getApiResultJson();
        }

character

BOM

UTF-8のBOM

\xef\xbb\xbf

この文字を先頭につけるとUTF-8のBOMになる。

Convert

IP/CIDR

// JavaScript
    /**
     * サブネットマスクをIPアドレス形式 (x.x.x.x/255.255.255.0) からCIDR形式 (x.x.x.x/24) に変換する。
     * @param {string} ipaddress - IPアドレス文字列 (x.x.x.x/x.x.x.x形式)。
     */
    toCIDR(ipaddress) {
      const [address, mask] = ipaddress.split('/')
      const segments = mask.split('.')
      const CIDR = segments
        .map((e) => Number(e).toString(2))
        .join('')
        .replace(/0*$/, '').length
      return address + '/' + CIDR
    },
    /**
     * サブネットマスクのCIDR形式 (24) をIPアドレス形式 (255.255.255.0)に変換する。
     * @param {number} cidr - ciderの数字。
     * @return {string} x.x.x.x形式のIPアドレス文字列。
     */
    cidrToIp(cidr) {
      const digit = 32
      const ip = ('1'.repeat(cidr) + '0'.repeat(digit)).substr(0, digit)
      return ip
        .match(/.{8}/g)
        .map((e) => parseInt(e, 2))
        .join('.')
    },

Algorithm

再帰処理

https://chatgpt.com/c/673d9bfe-2414-800b-9922-f94be6dbe950

配列の配列、オブジェクトのオブジェクトなど、再帰的な構造はけっこう遭遇する。

再帰関数で実装するほかに、スタックで処理する方法がある。

再帰関数のほうが簡単に実装できるが、関数呼び出しのオーバーヘッドがある。ネスト10-100程度くらいなら問題ない。

パフォーマンスや再帰中の細かい制御が必要なら、スタックが有利。ただし、実装がやや複雑。

最初は再帰関数で実装して、後でボトルネックになったらスタックというのも手。

https://chatgpt.com/c/6745228f-8b20-800b-8a41-bdaece8c03f5

再帰関数とスタックの他に、JSONなどの文字列にシリアライズして、文字列処理で対応するという手もある。

JSONPath/XPathなどの方法もあるが、基本的には外部ライブラリーが必要。

シンプルなケース以外は、再帰関数で処理したほうが結局シンプルな感じがする。

Other

コメントの著者名

https://chatgpt.com/c/67469d8d-7e64-800b-b82d-8c74f4e13c08

GNU socialのソースコードのコメントに著者名が大量にあった鬱陶しい。

大規模プロジェクトになると、編集者が膨大になる。VCSに任せて、本文には記載しなくていいと思う。

git blameで行単位で編集者が分かる。

UML

Tool

https://chatgpt.com/c/67441feb-d004-800b-96fd-0d9b04ffc628

What are the best UML tools for macOS? - Quora

  • デスクトップ
    • StarUML
    • ArgoUML
    • UMLet
    • OmniGraffle
    • edraw: 有料。
    • Umbrello
    • Modelio
  • クラウド
    • Visual Paradigm
    • Lucidchart: 有料。
    • Creately: 有料。
    • diagrams.net: モデルじゃない。
  • その他
    • PlantUML

UmbrelloとModelioはそれらと比較して何がよかったのだっけ?

Eclipse Papyrusが動作するならこれがいい。Eclipseは安定しているから、これのプラグインで動作するなら信頼できるだろう。

papyrusは一度試してダメだった気がするが。

Umbrello

Problem

altなどの重なり順番、アクティブの下になっちゃう

optの条件が表示されない。

Modelio

クラス図

  • 汎化 (generalization): 実線白矢印。継承。
  • 実現 (realization): 点線矢印。interfaceの継承。
  • 集約: 白ひし形。
  • コンポジション: 黒ひし形。子が単体で存在できない場合。親と生存期間が同一の場合。
  • 関連: 実線矢印。メソッド内インスタンスなど。
  • 依存: 点線矢印。引数やローカル変数、返却値。

Papyrus

Papyrus Dowloads

Papyrus Documentation

Tutorial

公式の[A slide-ware tutorial on Eclipse Papyrus usage for starters (2010-10-01)]を参考に基本的な使い方を学ぶ。

[File]-[New]-[Papyrus prooject]

これでプロジェクトを作ると、以下が [Project Explorer] に作られる。

  • <project name>
    • <project name>
      • di: ツールメタデータ。モデル作成のエントリーポイント。
      • notation: 画像データ。
      • uml: UMLモデルデータ。

このdiをダブルクリックして描画を開始する。

1個のプロジェクトでいろんな図に対応していて、モデルを流用できる形になっている。悪くない。これを使う。

画面構成

  1. Project explorer
  2. Model explorer: 一番重要。ここでモデル全体をツリーベースで管理する。
  3. Outline view: アウトライン
  4. Main toolber: ツールバー。
  5. Perspective: Model explorerの内容を使って作図する領域。
  6. Property view: モデルのエディター画面。

Model explorerがPapyrusの本質。ここでクラスとかインタラクションを定義しておいて、この定義をperspectiveの作図に使うイメージ。

クラス図やシーケンス図もModel explorerに所属していて、好きなだけ作れる。[New diagram]から作れる。

[New Child] でいくつか重要なモデルがある。

  • Package: ディレクトリ・フォルダーみたいなもの。これで他のモデルをまとめて整理できる。
  • Interaction: シーケンス図表現用のモデル。
  • Class: クラス。Interactionの型だったりする。UMLのベースで非常に重要。

Class

属性表示

クラス図にクラスモデルを配置しても、プロパティーやメソッドが表示されない。

右クリック-[Filters] で制御できる。

  • [Synchronized with Model] を選ぶと同期されて全部表示される。基本はこれで、一部だけ表示したい場合にここを外すのだろうと思う。
  • [Show/Hide Contents] で表示可否をチェックボックスで選べる。

Design

Atomic Design

最近のUIのコンポーネントの組み方。UIコンポーネントを粒度に分けて、ディレクトリー分けして流用するという考え方。

  • atoms: 原子。これ以上分割不能な最小単位。input/label/buttonなど。
  • molecules: 分子。atomsを組み合わせたり、atomsに多少修正したもの。入力フォーム、ナビゲーション、カードなど。
  • organisms: 有機体。分子+アルファ。入力フォーム+ヘッダーなど。複数の分子。
  • templates: テンプレート。複数の有機体。ヘッダー、メイン、フッターなど。
  • pages: ページ。テンプレートを使用したページ。

インターフェイスと抽象クラス

PHPでインターフェイスと抽象クラスを使う #PHP - Qiita

  • インターフェイスは、クラスに複数実装できるが、抽象クラスは1つしか継承できない。→不特定のクラスで、共通のメソッドを定義したい場合。
  • インターフェイスは、実装のあるメソッドを持つことができないが、抽象クラスは、実装のあるメソッドを持つことができる。→抽象クラスは、複数のクラスの、共通処理の中に、一部違う処理が入る場合、プロパティーが必要な場合などに使用する。

インターフェイス

  • メソッド宣言のみ。
  • static/constの場合に限定して、メソッド定義、定数もOK。

Config class

アプリケーションの設定を管理するクラスの設計方法。いくつか方法があり、議論がある。「Best way to provide configuration parameters for objects far away from the starting point - Software Engineering Stack Exchange」で特によく議論されている。

  1. シングルトン/グローバル変数: ただし、テストなどで並列アクセスが必要な場合に困ることがあるらしい。
  2. DI/設定クラス引数: これがよく支持されている。テストしやすいなど。グローバル変数への参照を渡すようなイメージ。ただし、依存性の伝播のように、上から下に設定を渡す際に、関係ない大量の設定を渡すことがあったりする。

2のDIが最近の主流。引数で値渡し相当にすれば、並列アクセス時も無影響。伝播の問題は設計の問題。

メソッドをmain関数で呼び出すことを想定して、必要なものだけ渡るようにして、余計なものは削除する。上位・下位の関係を明確にすれば、渡すだけのパラメーターを排除できる。

do-while/if

複雑なif文と相性がいい。

for whileの無限ループで最後にbreakでも同じか

do {
  if (true) break;
} while(false);

if文が複雑な場合、do-whileで囲んで、breakでスキップできる。gotoに近い。

GoF

基本的に、具象クラスを使わずに、インターフェイスや抽象クラスを使ってインスタンスを生成するというのが、共通する基本パターン。

これにより、いろんなケースに同じコードで対応できる。

Factory Methodパターン

なぜあんなに難しい?Factory Methodパターン - ecbeing labs(イーシービーイング・ラボ)

コンストラクターの代わりに、インスタンスを生成 (工場=factory) となるメソッドを使うから、FactoryMethodパターン。

引数の内容に応じて、異なるクラスを作成する。

ただ、Factory Methodパターンを採用すると、コード量が増えて複雑になる。

複雑でややこしいだけなので、基本的に使わなくてよいと思う。

Naming

camelCase

https://gnusocial.jp/notice/7694551

!it 命名規則のキャメルケース。これ英語前提です。関数名に英語以外を使うと破綻します。

getキーバリュー()みたいな関数の定義。日本語ですると境界がわからなくなるので、getキー_バリューみたいにアンダーバーで区切ったほうが分かりやすい。なるほど…

getMyVariable() vs myVariable()

getterとsetterの命名規則。

getVar()にするか、Var()にするか。C++だと後者のパターンがあったりする。getを省略できるので、省スペースになる。

ただ、コード補完で探しやすさがちょっと変わる。getを前置したほうがわかりやすいか。

namePrefixed() vs prefixedName()

https://chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85

名詞+修飾語 (形容詞) の場合のメソッドの命名規則。name+修飾語が複数ある場合name+修飾語がいい。オブジェクト指向でnameをオブジェクトとして扱う形に近い。name.methodみたいな。

例えば、nameMax、nameMinのような場合は後ろのほうが都合がいい。ただ、こういう場合はそもそもnameをオブジェクトにしてname.max()、name.min()にしたほうがいいという説がある。

そうではないならば、getPrefixedName()などが自然。getQueryString()など。StringQueryではない。

PHPでは以下のような命名規則が好まれる。

  • 動詞+修飾対象=getPrefixedName/isPrefixed()
  • 修飾対象+状態/修飾語=prefixdName

getPrefixedNameがいいか。後置修飾にしたいならば、そもそもオブジェクト+メソッドにすることを検討する。

map

連想配列とかハッシュ、オブジェクトなどでキーバリュー形式のデータ構造を扱うことがある。そういう変数の命名規則。

map_[key]_[value] のような形式にすると、キーとバリューが何を意味するか分かってわかりやすい。

array/foreach

foreach系のfor文ではキーとバリューを変数に格納して反復する。ファイルや配列に対して行うことが多い。

foreach (table as $row => $line)

その際の変数名は、上記のように$row/$lineにすると、行番号と行の値がはっきりしてわかりやすい。

いいえ。これは問題がある。ネストした場合などに命名規則を維持できない。

  • 配列、コレクション類: 複数形があるなら複数形。困ったらListの接尾辞。
  • 反復時。キーバリュー形式の場合、単数形_key/_value。valueだけの場合、単数形。また、_valueは単数形でもいいかもしれない。

上記の命名規則だとわかりやすい。

$rows = [[]];
foreach ($rows as $row_key => $row_value) {
  foreach ($row_value as $column_key => $column_value) {}
}


foreach ($row_list as $row_key => $row) {
   foreach ($row as $column_key => $column) {
   }
}


foreach ($rows as $row_index => $row_value) {
  foreach ($row_value as $column_index => $column_value) {
  }
}

value部分に単数形を使うと、検索時にkey部分もヒットして、作業しにくいかもしれない。基本はkey/valueの接尾辞がよいと感じる。

もっというなら、接尾辞の文字数が揃うので、keyよりindexのほうがよいかもしれない。ただ、indexは添え字の数字の意味合いが強いので、やっぱりkey/valueでいいか。

Function argument order

関数の引数は入力、変更、出力の順番にする。理由はこの順番で使うから。

https://social.senooken.jp/notice/67270

うーん。今晩は,CODE COMPLETEでC言語の関数の引数の順番を調べたりしていて,勉強時間がないな…

int func(入力,変更,出力)

この順番。理由は,この順番で使うから。

memcpyとかは例外が多い。

x = bの語順からきているからとの憶測がある。

https://okwave.jp/qa/q4202225.html

DB

PDOの真の力を開放する - PHPでデータベースを扱う(3): Architect Note

DBアクセスのモデル化。行をクラスとすると扱いやすい模様。

getterを作ったり、データの妥当性のチェックなどもできる。

select/insert/などはmapperでクラスとDB列名を対応付けて処理する。自前で実装する場合はこういうつくりがいいらしい。

データベース関係のデザインパターンがいくつかある。

  • Active Record
  • Data Mapper
Active Record pattern

テーブルレコードに対応するクラスを用意して、そのクラス自体にDB操作もさせる。

シンプルだが、複雑な操作が苦手。

エンティティーがテーブルと密接なため、例えばテーブル構造が変わった場合に大量に修正必要。

Ruby on Rails/Laravel+Eloquentなどで採用。

Data Mapper pattern

第14回 DataMapperの使い方 | gihyo.jp

テーブルのレコードをクラスにするのはARと共通。

ただし、DB操作用のクラスを用意してそちらでDB操作する。

その都合、1テーブルに2クラス必要。

User/UserMapperのような対応関係。

2クラス必要だが、テーブル構造が変わった場合でも基本はMapperで吸収できる。

JOIN

Active RecordもData MapperもJOIN時の扱いが一番重要。単一エンティティーしか扱わないならどちらも同じ。

基本はエンティティーのプロパティーに持たせる感じ。

datamapperパターンでjoinする場合、エンティティーの扱いはどうなるの?

`DataMapper`パターンで`JOIN`を行う場合、エンティティの扱いは設計次第ですが、いくつかの注意点があります。`DataMapper`パターンは、データベースのテーブルとエンティティの間にマッピングを行い、エンティティはドメインロジックを持ち、データベースアクセスの責務を持たないことが特徴です。そのため、`JOIN`の処理をどの層で行うかを慎重に設計する必要があります。

以下、`JOIN`を行う際のエンティティの扱いと実装方法について解説します。

      1. 1. マッパークラスでの`JOIN`実装

`JOIN`を伴う複雑なクエリが必要な場合、マッパーが直接`JOIN`を使って複数テーブルを組み合わせた結果を取得し、それを複数のエンティティとしてマッピングする方法があります。例えば、ユーザーと注文を持つシステムで、ユーザーとその注文を一緒に取得したい場合、`UserMapper`で`JOIN`を行い、結果セットを`User`と`Order`エンティティに分割してマッピングします。

```python

class UserMapper:

    def find_user_with_orders(self, user_id):

        sql = """

            SELECT * FROM users

            JOIN orders ON users.id = orders.user_id

            WHERE users.id = %s

        """

        results = self.db.execute(sql, (user_id,))

       

        user = User(results[0]['user_id'], results[0]['user_name'])

        orders = [Order(row['order_id'], row['product_name'], user) for row in results]

        user.orders = orders

        return user

```

この方法では、1つのSQLクエリで必要なデータをすべて取得し、エンティティのプロパティにそれぞれのデータを設定します。

      1. 2. リポジトリでの集約

`JOIN`を使わず、各エンティティを個別に取得した後、リポジトリが集約の役割を担う方法もあります。リポジトリが各エンティティの`Mapper`を呼び出し、必要なエンティティ同士を関連付けることで`JOIN`を再現します。例えば、まず`UserMapper`でユーザー情報を取得し、次に`OrderMapper`で該当ユーザーの注文を取得してエンティティ間で関連付けます。

```python

class UserRepository:

    def __init__(self, user_mapper, order_mapper):

        self.user_mapper = user_mapper

        self.order_mapper = order_mapper

    def get_user_with_orders(self, user_id):

        user = self.user_mapper.find(user_id)

        orders = self.order_mapper.find_by_user_id(user_id)

        user.orders = orders

        return user

```

UserテーブルとOrderテーブルがあって、あるユーザーの注文一覧を取得したい場合を考える。

結局、user.ordersみたいな感じで、エンティティーに外部テーブルのレコードを配列で持たせるつくりになる。

クロス集計する場合は、users[0].orderみたいな感じ。メインのエンティティーのプロパティーに持たせる。フラットじゃないのでちょっと気持ち悪い。が、まあ構造としてこうなるのは順当。

方法として、1回のSQLで取得するか、それぞれのエンティティーを取得してマージするか。1回のSQLでやったほうが当然いい。

Other

1対1-多対多

プログラミング言語でデータの関連付けをすることがある。

1対1の場合、配列、連想配列のキーバリュー形式のデータがぴったり。

多対多の場合。これも配列。二次元配列で基本は0要素目など。

$array[][]

Project

レガシープロジェクトの立て直し

https://chatgpt.com/c/67481a93-adc0-800b-81c4-20d763133002

1. 現状分析

(1) ソフトウェアの動作確認

現在の環境でアプリケーションを動作させる。

どの部分が機能していて、どこが問題かを確認する。

必要であればエラーログを確認する。

(2) 依存関係の調査

アプリケーションのライブラリやフレームワークのバージョンを調査。

サポートが終了しているもの、互換性が失われたものを特定。

(3) コードベースの状態評価

コードの品質 (可読性、設計、テストカバレッジ) を確認。

セキュリティリスクを特定する (例えば、脆弱性が放置されていないか)。

2. 計画立案

(1) ゴール設定

具体的な目標を設定 (例: パフォーマンス改善、保守性向上、セキュリティ強化)。

(2) 優先順位の決定

どの機能を維持し、どの機能を削除または置き換えるか決定。

ユーザーに直接影響を与える部分を優先。

(3) リスク評価とバックアップ

修正に伴うリスクを評価し、現行システムのバックアップを取得。

3. 環境整備

(1) 開発環境のモダナイズ

ローカル環境やコンテナ (Docker) を用意してテストを容易にする。

CI/CD パイプラインの整備。

(2) 依存関係の更新

サポートされていないライブラリやフレームワークをアップグレードまたは置き換える。

(3) セキュリティの確保

古いOSSの脆弱性を修正。

HTTPSの導入、認証強化、インプット検証など。

4. コードのモダナイズ

(1) リファクタリング

レガシーコードをよりモダンで可読性の高いコードに変換。

デザインパターンを適用して保守性を向上。

(2) テストの追加

ユニットテスト、統合テストを導入。

既存の機能が壊れないことを確認するための自動化されたテスト。

(3) フロントエンド/バックエンドの分離

必要に応じてモノリシック構造を分離し、モダンなアーキテクチャ (SPA、Microservices など) に移行。

5. 機能拡張とデプロイ

(1) 新しい機能の追加

必要に応じて、現代のニーズに合った新機能を実装。

(2) 運用環境でのテスト

新しい環境で徹底的にテストし、問題がないことを確認。

(3) 本番環境にデプロイ

ロールバック計画を準備しつつ、安全にデプロイ。

6. 継続的改善

(1) モニタリングの導入

エラーログやパフォーマンスを監視し、迅速に対応できる仕組みを導入。

(2) 定期的なアップデート

フレームワークやライブラリを継続的に更新し、レガシー化を防ぐ。

(3) コミュニティへの貢献

OSSとしての性質を活かし、変更内容をコミュニティに共有することでフィードバックを得る。

このプロセスを通じて、安定した動作を保ちながら徐々に近代化することが可能です。特に、「現状分析」と「環境整備」をしっかり行うことで、後続の作業がスムーズになります。

AI

対話AI

List

【2024年版】対話型AIサービスおすすめ11選を徹底比較!チャットボットとの違い・メリット・課題・選び方なども紹介 - NotePM

いろいろある。

Name
Bing
Perplexity AI
ChatGPT
Google Gemini

ChatGPT

Plan

ChatGPT | OpenAI

Free/Plusの2のプランがある。

Free Plus
金額 [USD/月] 0 20
機能 基本 アーリーアクセス
エンジン GPT-4o mini GPT-4/GPT-4o/GPT-4o mini
制限 - GPT-4oの5倍以上のメッセージ送信
その他 - データ分析、ファイルアップロード、ビジョン、Webブラウジング
画像生成 - DALL-E

送信可能なメッセージ数、エンジン、画像生成などが大きな違いだろう。

Account

公式サイトにアカウントの意味の説明がない。しかたないので、ChatGPTに質問。

ChatGPTに会員登録する意味は何ですか?


ChatGPTに会員登録する主な利点はいくつかあります。

1. **パーソナライズされた体験**: 登録すると、あなたの好みや過去のやり取りに基づいて、よりカスタマイズされた応答が得られます。

2. **履歴の管理**: 過去のチャット履歴を保存し、いつでも見返すことができるため、情報の確認が簡単になります。

3. **新機能へのアクセス**: 登録ユーザーは新しい機能やアップデートを優先的に利用できる場合があります。

4. **プレミアム機能**: 一部のサービスでは、会員登録をすることで、より高度な機能やサポートが提供されることがあります。

5. **セキュリティとプライバシー**: アカウントを持つことで、データの管理やプライバシーの設定をより細かく調整できます。

興味があれば、ぜひ登録を検討してみてください!他に質問があればお知らせください。

自分の過去の質問の履歴を見れるだけでも便利かも。

方法
質問の分割

https://chatgpt.com/c/673bdc0d-e0e0-800b-a22b-4fa19e64476c

Q. chatgptで質問するとき、連続して質問すると、同じURLで複数の質問が表示される。リロードして質問を分けたほうがいいのか?

A. どちらでも問題ない。が、質問が関連しているなら同じチャットで継続したほうがいい。直前の質問も文脈を考慮できる。完全に話が異なるなら分けたほうが後で整理したり、URLを共有したときにわかりやすい。

感想
2024-11-14 Thu

https://gnusocial.jp/notice/7806505

!it !ai 業務でPHPの開発作業をしていて、ChatGPTを使いだして便利に感じています。検索エンジンの代わりに使っています。

例えば、「laravel eloquentでリレーション先のテーブルの主キー名の取得方法は?」と質問します。

https://chatgpt.com/c/67354314-fbdc-800b-a4e4-65f96d1a8fb2

getRelatedというややマニアックなメソッドを教えてくれます[eloquent getrelated] で検索してもなかなかたどり着けないです。

こういう検索エンジンで検索しにくい質問で便利だなと思います。

検索エンジンで検索すると、的外れな情報も大量にヒットします。対話AIはそのごみの混ざった検索結果を分析した結果をコンパクトに返してくれます。対話AI使わなくても、検索エンジンで時間かければわかりますが、大幅に時間短縮できます。

大量の凡人健常者が取り組んだ方法論として決まりきったものは、記憶の問題、ただの神経衰弱です。こういうのを検索エンジンの改良版としてAIに任せるのはいい使い方だと思います。

個人的に、ただの知識、事実は重要度高くないと思いますが、一般社会では評価する側の頭が悪いので、これが重宝されます。

同僚や先輩に聞くより対話AIのほうがよほど頭いいです。話すことないです。聞くほうが時間の無駄なので。凡人はどんどん要らなくなります。

一方、私みたいなキチガイのデータは少ないので、検索エンジンやAIに聞いても出てこないです。世界で自分だけのオリジナルに専念するのがたぶんいいです。

2024-11-19 Tue

https://gnusocial.jp/notice/7867350

!ai ChatGPTが検索エンジンの改良版としてやっぱり便利。さっきこういう質問しました。

phpのメソッド名で、英単語の修飾語は前と後ろどちらがいい?例えば、namePrefixed()とprefixedName()のどちらがいい? https://chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85

私はこのレベルの細かい疑問がすぐ浮かぶのです。これを人間にきくと、頓珍漢な回答だったり、そもそも回答してもらえないし、何ならこういう質問した私がなぜかキチガイ扱いされて、微妙な雰囲気になって、質問できなくなって、ストレスが溜まって、居づらくなって早期退職になるんです。意味不明です。ただの質問にお気持ちの配慮とか面倒なので。

この間、 @yuriha に突っ込まれた件も、たぶん対話AIとお互い会話したほうが有意義だったんじゃないかとすら思います。相手も私に突っ込む前に対話AIと会話したほうが自分の主張の自己矛盾、頓珍漢さに気づけたんじゃないかとすら思えます。私が突っ込んでまーた私がキチガイ扱いされるのも回避されます。対話AIからの客観的な指摘なら、同じ内容であっても、キチガイの私が言うより納得しやすいでしょう?同じ内容なら対話AIのほうが凡人健常者にとっては、信じ込みやすいでしょ?

対話AIだとお気持ちの配慮いらないし、当たり前ですけど、キチガイ扱いされることもないので、快適です。元々対話AIには懐疑的でしたが、どちらかというと私のようなキチガイが凡人健常者の知識を拝借するためにあるような印象を持ちます。

検索エンジンでも調べることはできますが、めちゃくちゃ時間かかるんです。自分で複数の意見をみつけて、頭の中で比較検討して整理するので。これを一瞬でやってくれるのが楽。途中のデータ整理、目視は単純作業に近いのです。他のことに頭使えます。

もはや技術とか、ただの暗記の神経衰弱は別にいらないです。一般企業の上長とか、士業のように、単純知識でマウント取るタイプの仕事はこれで確かに駆逐されます。どうせ対話AIのほうが賢いのだから。知識量で勝てるわけないです。全世界の情報の集積結果なんだから。

凡人健常者の知識を拝借して、世界でだれにも真似できないキチガイ部分に専念できます。GNU socialの開発もこれでいけると思います。

Shell

Shell Command Language

Compound Commands

Shell Command Language

Case Conditional Construct
case word in
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac
  • 未マッチで終了ステータス0。
  • pattern部分: シェル展開が有効。他はglob。
  • |でOR検索相当。
  • 最後のパターンの;;は省略可能。if文のようにも使える。
  • 全パターンの捕捉は最後に*。空でもマッチする。?は最低1文字必要。

BREでは未対応な|のORマッチに対応しているのが最大の特徴。文法なのでコマンドを実行せず早い。grepを使わずにできるだけこちらを使ったほうがいい。

ワイルドカード

ワイルドカードで.始まりのファイルをマッチさせたい。

以下ならマッチするが、ブレース展開 (brace expansion) はPOSIX shでは使えなかった気がする。

echo {.*,*}

BOM

unicode - Adding BOM to UTF-8 files - Stack Overflow

ExcelでUTF-8ファイルを開けるように、UTF-8のBOMをファイルにつけたい。

printf '\xEF\xBB\xBF' > with_bom.txt

上記コードでBOMを最初に書き込んで、後は追記する。

awk

The Open Group Base Specifications Issue 7

変数

特別
  • NF: 列数。列の全表示などで使う基本的で重要な変数。
  • NR: 行番号。
スコープ

変数のスコープ

関数の仮引数のみ、ローカル変数扱いで、それ以外はグローバル変数。

文/statement

  • actions
    • if/else
    • while/do...while/for
    • break/continue
    • delete
    • next
    • exit
  • output
    • print
    • printf

関数

組込関数
  • Arithmetic
    • atan2
    • cos
    • sin
    • exp
    • log
    • sqrt
    • int
    • rand
    • srand
  • String
    • gsub
    • index
    • length
    • match
    • split
    • sprintf
    • sub
    • substr
    • tolower
    • toupper
  • I/O
    • close
    • getline
    • system

print/printfは関数ではなく、statement/文扱い。

ヘッダー出力、列別最大長さ出力。

awk -F, '{if(NR==1) print $0} {for(i=1; i<=NF; ++i){if (line[i] < length($i)) line[i] = length($i)}} END {for (i=1; i<=NF; ++i) {printf line[i]","}}' data/101542.csv

CSV

シェルスクリプトの実験のために作った POSIX 準拠 awk 実装の CSVパーサー (RFC4180対応) #ShellScript - Qiita

# csvparser.awk

## Usage
# awk -f csvparser.awk data.csv

# CSV の論理的な一行毎に呼び出されるコールバック関数(サンプル)
# row: 行番号(最初の行は1) len: フィールド数 fields: フィールドデータ
function callback(row, len, fields,  col, field) {
    for ( col = 1; col <= len; col++ ) {
        field = fields[col]
        gsub(/\\/, "&&", field)  # \ は \\ にエスケープする
        gsub(/\n/, "\\n", field) # 改行は \n にエスケープする
        print row ":" col " " field
    }
}

BEGIN { row = max_idx = 0 }
{
    idx = 0
    sub(/\r$/, "")
    while ($0 != "") {
        if (match($0, /^(["]([^"]|["]["])*["]|[^,"]*)(,|$)/)) {
            fields[++idx] = ""
        } else if (match($0, /^["]/)) {
            fields[++idx] = substr($0, 2)
            for (;;) {
                if (getline == 0) exit 1
                sub(/\r$/, "")
                if (match($0, /^([^"]|["]["])*["](,|$)/)) break
                gsub(/["]["]/, "\"")
                fields[idx] = fields[idx] "\n" $0
            }
            fields[idx] = fields[idx] "\n"
        } else {
            exit 1
        }
        field = substr($0, RSTART, RLENGTH)
        $0 = substr($0, RSTART + RLENGTH)
        lastcomma = sub(/,$/, "", field) > 0
        gsub(/^["]|["]$/, "", field) && gsub(/["]["]/, "\"", field)
        fields[idx] = fields[idx] field
    }
    if (lastcomma) fields[++idx] = ""
    while (idx < max_idx) delete fields[max_idx--]
    callback(++row, idx, fields)
    max_idx = idx
}

awkのCSVパーサー。先頭のBOMはあると認識できないので、tail -c +4でBOMを除外して使う。

tail -c +4 data/101543.csv | awk -f csvparser.awk 

Other

binary

POSIX準拠のシェルスクリプトでバイナリデータを扱う #Bash - Qiita

バイナリーデータの読込はodコマンド。なければhexdump。

書込はprintf。

head/tailの-cはPOSIXで使えたか?

root

リダイレクト出力

sudo権限でリダイレクト処理を行ってファイルに書き込む方法

リダイレクトはログインユーザーの権限でなされるらしく、root権限のある場所にファイル出力できない。

teeコマンドでやる。

pwd | sudo tee out.dat

teeコマンド実行する側でsudoが必要。


ログインシェルの確認

第 10 章 動作環境のカスタマイズ (Solaris ユーザ ログインシェルはGUIログインでも内部的にある。ログインシェルが読みこむprofileファイルなどは、ログイン時に、1回だけ実行したい処理の記述場所として最適。 SHELL環境変数にログインシェルのパスが入っている。

echo $SHELL
/bin/bash

OSの判別

OSTYPE環境変数に値があるのでこれで判別する。 例えば以下の値が入っている。

linux-gnu
darwin23

これらを検知して判定する。

case $OSTYPE in
  linux*) echo 'linux';;
  darwin*) echo 'Mac';;
esac

Configure

profile

bash の初期化ファイル .profile, .bashrc, .bash_profile の使い分けと管理方針 - A Memorandum 環境変数など~/.profileに全部のシェルの共通設定を記述して、~/.bash_profileなどのログインシェルやbashrcなどで参照するのがいい。

cmd.exe

Control block

for

あくまでコマンド。

nest

ネストはできない。二重ループしたければ、関数にしてそれを呼び出す。

bitsadmin

Windowsでのファイルダウンロードコマンド

Windows 7以降ではbitsadminコマンドがあり、これがwget相当となる。

書式:

bitsadmin /transfer <job name> <URL> <output path>

<job name>と<output path>は必須なので注意する。

certutil

Windowsでのハッシュの確認に使える。

certutil -hashfile file
SHA1 ハッシュ (対象 C:\moconavi\windows\Moconavi\ext\chromium\moconavium.exe):
e0da85b04b6970ac1f0c33db7a9ad607fdbd44eb
CertUtil: -hashfile コマンドは正常に完了しました。

rlogin.cmd

コマンドキーの送信を自動化できる?

rem rlogin.cmd

@Echo off
Set SERVER=192.168.0.0
Set USERNAME=
Set PASSWORD=

Cmdkey /generic:TERMSRV/%SERVER% /user:%USERNAME% /pass:%PASSWORD%
Start mstsc /v:%SERVER%
Timeout 5
Cmdkey /delete:TERMSRV/%SERVER%

実行中プロセスのパスの確認

出典: Show EXE file path of running processes on the command-line in Windows - Super User

wmic process get ProcessID,ExecutablePath
wmic process where "name='mysqld.exe'" get ProcessID, ExecutablePath
wmic process where "name='mysqld.exe'" get ProcessID, ExecutablePath /FORMAT:LIST

簡易編集モード/挿入モード

Windows 10のcmd.exeは [簡易編集モード] が有効になっており、コマンドプロンプトを左クリックすると、テキストの選択が始まる。テキスト選択中はコマンドの実行が止まる。長時間かかるコマンドの実行中に誤操作で止まると困るので、これは無効にしたほうがよい。

cmd.exeを起動-左上のアイコンをクリック-[規定値]/[プロパティ]-[オプション]-[□簡易編集モード] を選ぶ。

そのほか、 git log のような制御が移るコマンドを実行してしばらくすると、操作できなくなる。

[□挿入モード] にすると回避できる模様。

Web

URL

クエリー配列

やり方がいくつかある。

  1. CSV文字列で受取後分割: https://www.sakdor.net/test/?var=1,2,3 explode(",",$_GET[var]);
  2. 配列添字
    1. http://www.sakdor.net/test/?var%5B%5D=1&var%5B%5D=2&var%5B%5D=3
    2. http://www.sakdor.net/test/?var%5Ba%5D=1&var%5Bb%5D=2&var%5Bc%5D=3
    3. http:www.sakdor.net?var[0]=1&var[1]=2&var[2]=3

データが決まっているならcsvがシンプル。

CGI

https://chatgpt.com/c/67634332-a3b8-800b-87a2-e21bd21a1cfc

WordPressなどのWebアプリだとファイル拡張子が登場しない。これはいくつかの仕組みが組み合わさって実現されている。

  1. パーマリンク設定 によるクリーンなURL構造の生成。
  2. .htaccess(Apache)リライトルール によるURLの書き換えとルーティング。
  3. index.php を起点とする動的な処理。
  4. テンプレート階層 に従って適切なPHPファイルを呼び出す。

.htaccessでindex.phpにリダイレクトして、index.phpから全て処理している。これにより省略できている。

同じ用に、アプリ側が対応していれば、index.fcgiに全部リダイレクトして、パスを解釈してくれるなら、/でのアクセスもできる気がする。

apache - How can I run a FastCGI script in root url (/ - without path)? - Stack Overflow

HTTP

RFC 9110: HTTP Semantics

Content-Disposition

Content-Disposition - HTTP | MDN

RFC 6266 - Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)

Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"

filenameでファイル名を指定する。ここの値は二重引用符で囲む。スペースを含む場合に必須になる。

multipart/form-data

rfc7578

ファイルアップロード用のMIME type。

リクエストヘッダー

Content-Type: multipart/form-data; boundary=--hogehoge

リクエストボディー

--hogehoge
Content-Disposition: form-data; name="user_name"
Content-Type: text/plain

test
--hogehoge
Content-Disposition: form-data; name="email"

sample@mail.com
--hogehoge
Content-Disposition: form-data; name="gender"

male
--hogehoge
Content-Disposition: form-data; name="user_profile" filename="image.jpeg"
Content-Type: image/jpeg

\xff\xd8\....
--hogehoge--

ヘッダーでmultipart/form-dataを明記して、ボディーでデータを指定する。

curlコマンドでPOSTする, 様々な形式別メモ |

curlでの送信理由。

-Fで送信データをname=data形式で指定する。ファイルの内容を指定する場合、@filenameで指定する。これを指定すると、リクエストボディーのfilename扱いにしてくれる模様。-Fを指定すると、-H 'Content-Type: multipart/form-data'が自動付与される。たぶん、-dと同様に-X POSTもつく。

curl -X POST -F file1=@/var/tmp/sample.jpg https://xxxxx.net/xxxxxx

データとテキストを同時送信したい場合、-Fで複数指定する。

curl -X POST -F 'age=30' -F file1=@/var/tmp/sample.jpg https://xxxxx.net/xxxxxx

curlだと上記のboundaryなどをうまくやってくれるのだと思う。

リクエストボディー全体をファイルデータにする場合。

curl -X POST -H 'Content-Type: image/jpeg' --data-binary @/var/tmp/sample.jpg https://xxxxx.net/xxxxxx

IP address

出典: 固定IPアドレスの取得方法 ~実は簡単!フリーランスの方も必見です~|VPN活用日記|トピックス|グローカルネットの快適VPN【公式】| 株式会社グローカルネット

自宅サーバーを行う際、固定IPアドレスが必要になる。

取得方法がいくつかある。

  • 契約しているプロバイダでオプションとして申し込む方法
  • 固定IPアドレスに対応しているSIMを契約する方法
  • VPNを利用した固定IPアドレスの提供会社を利用する方法

VPNの固定IPアドレスが安いらしい。ryoかsuwakoが解説していた気がする。

Authentication

認証方式がいくつかある。HTTPで定義される認証方式 (HTTP認証) が有名。

Basic認証

出典: Basic認証 - Wikipedia

Authorization HTTPヘッダーにBasicのあとに [username:password] をBASE64でエンコードして送信する認証方式。

GET /private/index.html HTTP/1.1
Host: example.com
Authorization: Basic cm9vdDpwYXNzd29yZA==

盗聴や改ざんが簡単だが、シンプルという利点がある。

Basic認証のキャッシュを削除する(ログアウトする) | DevelopersIO

ログアウト時は、hoge@domainのようにパスワードを省略した任意のユーザー名でログインを試みて既存のログイン状況を上書きする模様。

Digest認証も共通。

Digest認証

Basic認証・Digest認証・Form認証をざっくり理解 #Security - Qiita

HTTP標準の認証。Basic認証とほぼ同じ。ただし、パスワードをハッシュ化している。そのため、DBのパスワードが流出した場合に比較的安全。

OAuth

Ref

OAuth (オーオース) 権限の認可のための標準。OAuth 2.0が最新の標準。

以下が登場人物。

  • resource owner: あるサイトのユーザー。
  • resource server: あるサイトのユーザーのデータの保有サーバー。
  • clent: クライアントアプリ。リソースサーバーのデータを使用したい。
  • authorization server: クライアントにサイトへのアクセスを認証するサーバー。アクセストークンを発行して行う。

アクセストークンが実質的なパスワードのようなものだが、resource serverのパスワードを直接渡していない点が重要な違い。パスワードを直接渡さないことで、機能別に権限を細かく利用可否を制御できる。

処理の流れ。

  1. client->resource owner: Authorization Request。ここでユーザーが手操作でアクセスを承認する。
  2. client<-resource owner: Authorization Grant。
  3. client->authorization server: Authorization Grant。承認された情報でアクセストークンを要求。
  4. client<-authorization server: Access Token
  5. client->resource server: Access Token。アクセストークンでアクセス。
  6. client<-resource server: Access Token

Consumer Key/Secret: アプリ識別用のID/PW。

Access Token: サイトにアクセスするためのパスワード。

API

複数レコードの登録

複数レコードの登録・更新・削除のREST APIについて調べてみた話(+@ Graph API) - junode | 個人開発ブログ

既存のAPIは単一リソースの処理しかないことが多い。JavaScriptなどで単一リソースを何回も呼べばいいというのはそうだけど、JavaScriptなしでは動作しない。一括処理用のAPIを作るしかなくないか?

REST WebAPIのプラクティス | yamarkz.com

delete_bulkなどのような一括処理用のAPIを作るしかない。内部的には単一処理のAPIを作る感じだったとしても。

パラメーター

json - REST API Best practices: args in query string vs in request body - Stack Overflow

パラメーターの指定に3種類ある。

  1. リクエストボディー
  2. クエリー
  3. パス

パスはIDなどを指定する場合だけわかりやすい。それ以外のオプションはクエリーのほうがいい。

ボディーは、通常サーバーのアップロード・ダウンロードデータとして使われる。クエリーはデータの指定に使う。

この原則に従うとシンプルだろう。

  • URIには長さの制限がある。
  • ボディー
    • 引数が非常に多い場合。
    • 画像などバイナリーデータ。
    • キー・値構造を持たない場合。
  • クエリー文字列
    • 引数を簡単に確認できる。
    • 共通の引数の場合。

検索機能のGET/POST

検索機能にGETとPOSTのどちらを使うか?という議論がある。

データ登録するわけなじゃないのだから、GETがいいんじゃない?

POSTだと、JSONをそのまま送れるので、複雑なケースに対応できる。特に、配列の送信が重要。

GETのほうが検索条件をブックマークにできたり、URLを共有できるので、基本は便利。

ただし、検索などのパラメーターが長くなる場合、使用できない。そもそも検索でそんなに長いパラメーターというのがまずいかもしれない。2000文字あれば十分という説がある。

レート制限対策

いろいろ方法がある。

  • cronなどでデータをサーバー上 (DBなど) に定期保存して、保存データを表示させる。
  • 配列を利用して、1回のリクエストでまとめて取得する。
  • インターバルを設ける。
  • HTTP 429/413を検知して、リトライする。

指数関数的バックオフ

wait_interval = base * 2^n +/- jitter
  • wait_interval は、API が HTTP 429 で応答した場合に、システムがリクエストを再試行するまでの時間となります。
  • base は最初の間隔、つまり最初の再試行までの待ち時間です。この値には3000msを使用することをお勧めします。
  • n は、現在の呼び出しの前にリクエストが通らなかった数です。複数のスレッドやプロセスを使用して並行してAPIを呼び出している場合、nの値は現在のスレッド/プロセスにスコープされます。この値は、現在のスレッド/プロセスが、最後に成功した応答から何回 429 "Too Many Requests" エラーに遭遇したかを表します。
  • jitter は 0 から base の間の乱数です。これは、複数のスレッド/プロセスが全く同時にAPIを呼び出さないように、リクエストを少しずつ分散させるために使用されます。システムが待機するたびに、この乱数値を再計算し wait_interval の合計に加算するか減算するか、ランダムで選択してください。

バックエンドとフロントエンドの分離

https://chatgpt.com/c/6747e923-6174-800b-8816-dd741721de45

SPA (Single Page Application) やJAMStackの影響で、バックエンドはデータを返すだけで、画面描画はフロントエンドが全部するというのが最近の流行。

SSR (Server Side Rendering) とCSR (Client Side Rendering) の違い。フロントエンドの高度化や分業などが理由とのこと。

SSRの利点。

  • SEO
  • 初期表示。
  • 匿名。

SSRの課題。

  • サーバー負荷: データとHTML作成を同時に行うから。
  • 分散困難:

キャッシュの活用がポイントになるとのこと。

Network

ssh

ssh-addの自動登録

ssh agentに秘密鍵の登録は以下のコマンド。

ssh-add <秘密鍵のpath>

ただし、上記コマンドは再起動すると登録が消えるので毎回必要。

~/.ssh/configに以下の内容を記入しておくと、次回からkeychainから自動で読み込まれるらしい (macOS で再起動しても ssh agent に秘密鍵を保持させ続ける二つの方法 #SSH - Qiita)。

Host *
  UseKeychain yes
  AddKeysToAgent yes

うまくいかなかった。

ssh-addをPC起動する度に自動的に実行させるための設定 | AIFAN

id_rsaの場合はIdentityFileを省略できるが、それ以外は指定が必要な模様。

Host *
  UseKeychain yes
  AddKeysToAgent yes
  IdentityFile ~/.ssh/id_ed25519
ssh経由でのリダイレクト出力

bash - How to remotely write to a file using SSH - Super User

ssh経由で標準入力内容からファイルをリダイレクトで作成したいことがある。

sshのコマンド部分を文字列にすればOK。

ssh user@remotehost -T "cat > /remotefile.txt" <<-EOT
Some text
EOT

-Tで擬似端末を無効にしている。

パスフレーズの省略

SSH多段接続時とgit cloneでSSH鍵参照時に、パスフレーズを要求される。毎回要求されるのが手間。これを省略する方法がある。 ~/.ssh/configに以下の設定を記述する。

Host *
 AddKeysToAgent yes
 UseKeychain yes
 IdentityFile ~/.ssh/id_ed25519
  • AddKeysToAgent=yesにすると、ssh-agentの実行時に自動的に鍵を追加する。
  • UseKeychain=macOS専用。OSのキーチェーンからパスフレーズの検索を試みる。
  • IdentityFile=SSH秘密鍵の絶対パス。デフォルトは~/.ssh/id_rsa。

上記3点で自動入力を試みる。 macOSで行う分には上記だけでパスワードは聞かれない。これをリモートでもやりたいなら、ssh-agentに登録が必要。 ログイン時に1回実行してくれたらいいので、ログインシェルの設定の~/.bash_profileに以下を記述。

echo 'ssh-add --apple-use-keychain' >>~/.bash_profile

これで端末の起動時に鍵を自動登録してくれるので、リモートでもパスフレーズを要求されない。

ssh_config

ssh_config(5): OpenSSH SSH client config files - Linux man page

重要な設定・構文がある。

TOKENS

macのman ssh_configに詳しい。

使用可能な指令が限定されている。

HostName (Macのみ)

  • %h=リモートホスト名。Hostの指定部。
  • %p=リモートポート。
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!

ssh example.comなどを実行すると、IPアドレスの振り直しなどで、ホストの公開鍵が変わっていた場合、中間者攻撃への対策として失敗する。

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
SHA256:.
Please contact your system administrator.
Add correct host key in /Users/z.ken.senoo/.ssh/known_hosts to get rid of this message.
Offending RSA key in /Users/z.ken.senoo/.ssh/known_hosts:1
Host key for [example.com]:3023 has changed and you have requested strict checking.
Host key verification failed.
Connection closed by UNKNOWN port 65535
Connection closed by UNKNOWN port 65535

$HOME/.ssh/known_hostsの該当行を削除すれば解決する。以下のコマンドでも対応してくれる。

ssh-keygen -R example.com

curl

HTTPの通信のコマンドラインでの確認でよく使う。

Basic

curl - Tutorial

  • -X: メソッド指定
  • -d/--data-urlencode: リクエストボディー (key=value)を指定。-X POSTも自動指定になる。
curl -H "Content-Type: application/json" -d '{"name":"佐藤", "mail":"sato@example.com"}' localhost:5000/api/v1/users

JSONで送信する場合、ヘッダー指定が必須。

*-F: multipart/formのform指定。

curl -F "coolfiles=@fil1.gif;type=image/gif,fil2.txt,fil3.html"
  http://www.example.com/postit.cgi

@でfilename相当の指定。;でmime typeも指定できる。

@/</;type=自体を送信したい場合、-Fではなく、--form-stringを指定する。

curl: (60) SSL certificate problem: self-signed certificate

Ref: curlで「自己署名証明書」を受け入れるには【curl: (60) SSL certificate problem: self signed certificate】 | LFI.

--insecureオプションを指定すると、localhostなどでの自己署名証明書を許可する。

curl: Failed writing body

pipe - Right After piping to "head"/"tail": "curl: (23) Failure writing output to destination" - Ask Ubuntu

以下のようにhead -n 1を指定するとcurlがエラーを出力する。

curl -H "Content-Type: application/json; charset=utf-8" -H "X-HD-apitoken:$TOKEN"         -d "{\"dbSchemaId\":$dbSchemaId, \"limit\":1, \"offset\":$offset}"         https://$DOMAIN/$ACCOUNT/api/csvexport/version/1.0 | head -n 1
curl: Failed writing body

curlは標準出力に全部書き込めたかチェックしているようで、head -n 1で切り捨てたらcurlはエラーになる。

対策は、curl -sで出力を抑制するとのこと。これで解決。

Teleport

踏み台サーバー (Jump server/Jump host) をよりよく管理するためのサーバーソフトウェア。

アクセスログなどを一元管理できる。商用版とオープンソース版がある。

基本的にteleportのサーバーを一度経由して、各種の踏み台サーバーにアクセスする。経由先が1個増えるが、そのおかげで監査ログを取得できたり、権限などを一括管理できる。

ただ、teleportで監査ログを残すには、基本的にtshを経由する必要があり、既存のIDEなどのssh想定のソフトだと工夫が必要。tsh経由でやったり、rsyncで間にtshを挟むような工夫が必要。

tsh

teleportのコマンドラインクライアント。

tsh loginでteleportにログインする。

環境変数

tsh CLI reference | Teleport Docs

  • TELEPORT_PROXY: teleportプロキシーサーバーのアドレス。重要。
ProxyJump+ProxyCommand

How To Use SSH ProxyJump and SSH ProxyCommand

https://goteleport.com/blog/ssh-proxyjump-ssh-proxycommand/

~/.ssh/config のProxyJumpとProxyCommandの違いを整理する。

どちらも中間サーバーを経由したリモートサーバーアクセスの指令。

  • ProxyJump: 最も簡単な方法。OpenSSH v7,5以上で使用可能。中間サーバーでポート転送対応が前提条件。ProxyJumpは内部でProxyCommandを使う。
  • ProxyCommand: ProxyJump搭乗前の方法。中間サーバーを介して標準入力と標準出力を転送して機能。

ProxyJumpの方が現代的だが、ProxyCommandの方が柔軟性が高い。

ProxyJumpの使用例。

ssh -J <jump server> <remote server>ssh -J <jump server1>,<jump server2>,<jump server3> <remote server>

ProxyCommand

ssh -o ProxyCommand="ssh -W %h:%p <jump server>" <remote server>

~/.ssh/configの例。

Host remoteserver

 HostName 192.168.200.200

 User dev

 IdentityFile ~/.ssh/<your_key>

 Port 2048


 ## sample for ProxyJump

 ProxyJump user@<jumpserver>


 ## sample for ProxyCommand

 ProxyCommand ssh -W %h:%p <jumpserver>

ssh remoteserver で<jumpserver> 経由でremoteserverに接続できる。

一般的に、ProxyJumpが推奨される感がある。ただ、teleportを導入している場合、ProxyJump/ProxyCommandを使うと、tshを経由していないのでteleportにログが残らないらしい。

tsh経由ssh

ProxyJump/ProxyCommandを使わない場合、以下の形式でtshを使ってアクセスするのが基本。

tsh ssh 踏み台サーバーホスト名

tsh sshでteleportサーバーが管理している踏み台サーバーが見えるので、そこに接続できる。tshの後のsshは基本的に通常のsshと同じなので、sshの後にsshのコマンドを連鎖でき、対象サーバーにも一発でアクセスできる。

tsh ssh -At <jump host> ssh -A <target host>

-tでttyに繋いで標準入出力を接続。-Aはフォワーディング。ローカルのssh-addの情報などを連携できる。

<jump host>の~/.ssh/configを用意しておくことで、<target host>にホスト名を指定したりできる。

ProxyJump/ProxyCommandと異なり、これだとちゃんとログを残せる。

tsh経由scp

tsh経由の踏み台サーバーへのファイル転送はやや工夫が必要。

tsh scpというコマンドが一応ある。が、これはネストなどには未対応。やる場合、以下のように2回実行になる。

FR=test.file TO=/path/to/test.file
tsh scp $FR <jump host>:$TO; tsh ssh -At <jump host> scp $TO <target host>:$TO

高ではなく、rsyncを使えば一発でいける。

rsync -e "tsh ssh -A <jump host> ssh" ./test.file <target host>:~/

これが基本。

PhpStorm

JetBrains SFTP | Teleport Docs

teleportの公式にマニュアルがあるが、記述が非常に不親切。これだと踏み台サーバーにしかアクセスできない。その先にアクセスできない。

多段SSHの設定を残しておいて、ファイル転送だけrsyncで行う形になる。

PhpStormのSSH configurationsのホスト名がスクリプトの引数に渡されるので、踏み台からAWSにsshでログインするホスト名やパソコンの~/.ssh/configのHostとの一致必要な点に注意する。

USERNAME=
IPV4=
VPCID=
cat <<-EOT >>~/.ssh/config
Host $VPCID
  ForwardAgent yes
  User $USERNAME
  ServerAliveInterval 30
  SendEnv -LC_* -LANG
  ProxyJump $USERNAME@teleport.security:3023
   
Host $USERNAME
    ForwardAgent yes
    ProxyJump $VPCID:22
    User $USERNAME
    Hostname $USERNAME.example.com
    ServerAliveInterval 30
    SendEnv -LC_* -LANG
   
Host $USERNAME.$VPCID
    # for automatic upload by PHPStorm
    LocalForward 22224 $USERNAME.$VPCID:22
    # for XDebug
    RemoteForward 9000 localhost:9000
    ForwardAgent yes
   
Host db-*
  HostName $IPV4
  LocalForward 3307 localhost:22
  ProxyCommand ssh $VPCID -W %h:%p
  ForwardAgent yes
   
Host *
    AddKeysToAgent yes
    PasswordAuthentication no
    User $USERNAME
    ForwardAgent yes
    ServerAliveInterval 30
    IdentityFile ~/.ssh/id_ed25519
    # for macOS
    UseKeychain yes
EOT

こんな感じの多段SSHの設定を用意。 踏み台サーバーにも同じホスト名でアクセスできるように、以下のような内容の~/.ssh/configをまだならば設定しておく。

AWS_HOSTNAME=

IPV4=

VPCID=

tsh ssh -A $VPCID "cat >>~/.ssh/config" <<-EOT

Host $AWS_HOSTNAME

 HostName $IPV4

EOT


rsync executable

rsyncで使用する (-eオプション)、以下の内容のシェルスクリプトを作成して実行権限を付与して任意の場所 (例: ~/project/tsh_ssh.sh) に配置する。

cd ~/project/

cat <<-'EOT' >tsh_ssh.sh

tsh ssh -A <jump host> ssh $@

EOT

chmod +x tsh_ssh.sh


PhpStorm設定

PhpStormで以下を設定する。

  • [Tools]-[Deployment]-[Configuration]
  • [+]-[SFTP]
  • [Create New Server]-[New server name: 任意の名前 (例=rsync)]-[OK]
  • [Connection] タブを以下に設定。
    1. Type=SFTP
    2. SSH configuration=以下を設定。
      1. Host: <ホスト名> (例: ~/.ssh/configと踏み台サーバーの~/.ssh/configのホスト名と同じにする)
      2. User name: ユーザー名
      3. Port: 22
      4. Authentication type: OpenSSH config and authentication agent
    3. Root path=転送先のベース。
    4. [☑️Use Rsync for download/upload/sync]
    5. Rsync Settings=以下を設定。
      1. Shell executable path=tsh_ssh.shのパス (例=~/project/tsh_ssh.sh)
  • [Mappings] タブを以下に設定。
    1. Local path: ローカルパソコンのディレクトリー
    2. Deployment path: /
    3. Web path: /
  • [Settings]-[Build, Execution, Development]-[Development]-[Options]-[Upload changed files automatically to the default server]=[On explicit save action]
    1. ☑️Delete remote files when local are deleted

以上で完了。後は同期したいファイルをPhpStormで開いて、右クリック-[Deployment]-[Upload to]/[Download from] でファイル転送できる。

[☑️Use Rsync for download/upload/sync] のチェックを外せば、rsyncを使わないファイル転送になる。

Wireshark

TLS

Ref: SSL/TLSの復号#1 ~Wiresharkの設定~ | 東陽テクニカ | “はかる”技術で未来を創る | ワン・テクノロジーズ・カンパニー.

Wiresharkで通信パケットを確認する場合、デフォルトでTLSで暗号化されているので、内容がわからない。WiresharkでTLSに対応しておく必要がある。

[Preferences]-[Protocols]-[TCP] を選ぶ。

  • ☑Allow subdissector to reassemble TCP stream
  • ☑Reassemble out-of-order semgemnts

上記をチェックしておく。デフォルトでチェックされていた。

続いて、セッションごとのPre-Master Secretを登録する。

Chrome/Firefoxだと、環境変数SSLKEYLOGFILEを設定すれば、このファイルにTLSセッションキーを出力するので、これをWiresharkで読み込むことで、復号対応する。

以下のコマンド相当で、任意のファイル・場所にログファイルを指定する。

export SSLKEYLOGFILE=/tmp/sslkey.log

Macだとlaunchctlで設定しておくといい。これでWebブラウザー経由の場合は見えるようになる。

Security

DoS攻撃

いくつか対策方法がある。

サーバーログにIPアドレスが残るから、それで攻撃元の国を特定して、該当国を一括アクセス拒否。これが効果あるかもしれない。

攻撃元の国は途上国とかが多いだろうから。IPアドレスは簡単に変更できるが、国を変えるのはたいへんだろう。

バリデーションの実装

基本的に、バックエンドで主にチェックして、フロントエンドはUXの向上目的で実装する。データの重複チェックはDBアクセスが必要だったりするから。また、API経由などフロントがそもそもないケースもある。

ただ、社内システムのような、画面経由でしか使わない。悪者がほぼいないと思われるケースは、フロントエンドでの検証だけでも十分に感じる。

二重送信

submitボタンのダブルクリック、リロード、ブラウザーバック・フォワードなど、フォーム周りで注意が必要な保安要素がある。

  1. ボタン連打
  2. ブラウザーバック
  3. リロード (PRG)

項目ごとにすべき対策が異なる。

連打

基本は、ボタンのsubmitのイベント内でdisabled=trueでの無効化。

似た考え方で、スプラッシュのモーダル表示もあり。これがわかりやすいかもしれない。

$("form").submit(function() {
  var self = this;
  $(":submit", self).prop("disabled", true);
  setTimeout(function() {
    $(":submit", self).prop("disabled", false);
  }, 10000);
});

停止にしたら、二度通せなくなるので、タイムアウトで戻すとよい。

Browser

Chromium

Extension

Chromme系で愛用拡張機能を列挙する。

devtool/開発者ツール

イベントリスナー

要素に設定されているイベントを調べよう - ゆずめも

[Elements]-[Event Listeners]-[handler]-右クリック-[Show function definition] でイベントリスナー関数の定義を確認できる。

イベント監視

How to find out which JavaScript events fired? - Stack Overflow

monitorEvent関数で監視できるらしい。他に、FirefoxのFirebugのlog eventsでも監視できるらしい。

Network conditions

開発者ツールの[Network]タブを開いてリロードしても、[No internet]と表示されることがある。

これはオプション設定の問題。上のツールバーの[Disable cache]の右が[Offline] だとこうなる。これを[No throttling]にすると解決する。クリックミスだと思われる。

Safari

Windows Safari

一応ある。2012-05-09のSafari 5.1.7までWindows版が提供されていた。DL1531。

開発者ツール

PCでスマホサイトを見る方法 – Safari編|東京渋谷のWeb制作会社・ホームページ制作会社|株式会社イー・バード

Safariの開発者ツールは癖がある。

[設定]-[詳細]-[☑️Webデベロッパ用の機能を表示]

[開発]-[レスポンシブデザインモードにする]

Other

Tool

いくつかWeb関係の開発で役立つツール集を公開しているサイトがある。

localhost

RFC 6761 で規定。RFC 2606で予約。DNSに登録されることはないため、テスト目的で使用可能。ループバック (送信元にそのまま返す) インターフェイス。

IPv4=127.0.0.1/IPv6=::1とされている。

Shared Host

Free

無料で使用可能な共用ホスティングサービスがある。

スタードメイン無料サーバー

ドメインをセットで利用する必要があるものの、スタードメインのスタードメイン無料サーバーがけっこういい。

無料レンタルサーバー | スタードメイン - ドメイン取得 100円(税込)~

jpドメインの金額が相場の中では安い方で、それに無料サーバーがついていくる点。

  • ディスク容量 20GB
  • DB 1GB

ただし、SSHやコマンドは使えないので、FTPでWordPressを展開して設置するとか、そういう簡単な使い方だけ。ただ、それでもWordPressでWebサイトを構築するくらいなら十分だと思う。

CORESERVER

メール

情報

ルールが特殊なので注意する。

ゴミ箱に振り分ける場合。

順1 で[./.Trash] を指定

順2

  • 条件:  [.*]
  • 処理:  ./、に振り分ける

条件部分には正規表現が使えるように見える。

破棄にしないといけない。転送する場合、カスタムフィルターの中に転送を入れる。条件を.*にする。

カスタムフィルターにくせがある。

  • エスケープ(\を前置する)が必要な文字は「'」「"」「|」「`」「~」「?」「!」

Value Domain ネットde診断 byGMO

2024-06-07 Friからバリュードメイン系の利用者に無料で提供しているセキュリティー診断ツール。

CGI

CORESERVERでのCGIの設定方法がある。

CORESERVERのFastCGI版PHPとCGI版PHPの設定方法
項目 FastCGI CGI
バージョンの変更 管理画面 .htaccess内の

AddHandler application/x-httpd-phpcgiXX .php

設定ディレクトリー /virtual/<username>/public_html/.fast-cgi-bin/
CGIの実行ファイル phpXX.fcgi phpXX.cgi
PHPの設定ファイル phpXX.ini php.ini
設定の反映タイミング バージョン切替時 即時

~/public_html/.fast-cgi-bin/のphpXX.fcgi phpXX.cgiがCGIの実行ファイル。このファイルか最後の行のexecのパスを変更すると、自前コマンドに変更可能。

FastCGIは管理画面からバージョンを変更したタイミングで反映される。ただ、ファイル拡張子が.phpじゃないとこのFastCGIが実行されない模様。

CGIは.htaccessに以下の内容を記述してCGI板PHPのバージョンを指定する。

AddHandler application/x-httpd-phpcgiXX .php

cgiのファイルには実行権限が必要。

chmod +x py.py

拡張子がないとダメな模様。加えて、.htaccessに以下の記述。

AddHandler cgi-script .py

これでpy.pyで動作はする。

拡張子じゃなくてファイル名で実行したい場合、SetHandlerでしていする (AddType, AddHandler, SetHandlerの違い – senooken JP)。

<FilesMatch py$>
    SetHandler cgi-script
</FilesMatch>

これでpyでもアクセスできる。

FastCGI版の場合、以下のような設定でファイル名でマッチさせれば実行できそうな気もするが。

<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

500

<FilesMatch gnusocial$>
        SetHandler application/x-httpd-php
</FilesMatch>

pythonがphpとして認識され、テキストがそのまま表示される。

SetHandler fcgid-scriptにしたらFastCGIで動作する。プログラムがFastCGI対応になっている必要がある。

<FilesMatch gnusocial$>
        SetHandler fcgid-script
</FilesMatch>

Analytics

Exam

## About

https://gnusocial.jp/notice/4506679

### 全般

- マーケティング・ビジネス実務検定

- IMA検定

- Web検定

- ネットマーケティング検定

### 解析系

- ウェブ解析士

- GAIQ

- 統計検定

- Webアナリスト検定

GAIQが無料だしどうせ使うからいいかな。

https://wacul-ai.com/blog/access-analysis/google-analytics-method/gaiq/

https://www.plan-b.co.jp/blog/seo/12792/

## URL

- https://ceres-inc.jp/business-tips/recommended-webmarketing-shikaku/

- https://mynavi-creator.jp/blog/article/qualification-for-web-marketer

- https://www.icloud.co.jp/article/exam/features-and-5-acquisition-benefits.html

- https://digitor.jp/textbook/web-analytical-qualification/

Tool

サイト分析用のツールがいくつかある (2023年ブログランキング!おすすめブログランキングサイト比較【一般人向け】)。

  • SimilarWeb
  • Ubersuggest
  • ahrefs
  • Googleキーワードプランナー

閲覧数取得

出典: GoogleAnalyticsで自サイトの人気記事ランキングを表示する方法 | アフィリエイトJAPAN

  • [行動]-[サイトコンテンツ]-[全てのページ]
  • [表示する行数]=5000
  • [エクスポート]=TSV

流入元特定

会員登録画面の流入元探索方法について - Google アナリティクス コミュニティ」どのページから会員登録があったか、会員登録に結びつく記事は非常に重要。

こんにちは。

探索レポートでユーザーセグメントを作成する集計方法はいかがでしょうか。

・自由形式レポートを作成

・セグメント作成 > ユーザーセグメント

・条件は page_view > パラメータ page_location > 含む:会員登録画面のURL を指定

・「会員登録画面閲覧ユーザー」などセグメント名をセットして保存

・探索レポートにセグメントを適用

・ディメンション:セッションの参照元 / メディア、ランディング ページ + クエリ文字列

・指標:セッション

ご確認よろしくお願いいたします。

※ページ閲覧の発生しなかったセッションはランディングページが (not set)になります。

 開きっぱなしのタブから再訪問するセッションなどが該当します。ご参考までに。

PMProでも似たような回答。

Google Analytics 4 can track ecommerce conversions and then assign page value to posts that were a part of their conversion path for that engaged session.

Server

httpd

Apache HTTP Server

About

httpdの利用可能な情報。

https://chatgpt.com/c/6761f851-df0c-800b-86e9-1624b458d66d

# 使用可能な指令一覧
apachectl -L
httpd -L

# 使用可能なモジュール一覧
apachectl -M
httpd -M

.htaccessで使用可能な指令の一覧。

.htaccessで使用可能な指令一覧 – senooken JP

Operation

サーバーの稼働や状態確認などで重要な操作がいくつかある。systemd前提。

ログ・状態確認。

sudo systemctl status apache2

sudoをつけないと詳細ログを確認できない。

sudo systemctl restart apache2
sudo systemctl start apache2
sudo systemctl stop apache2

Access Control

DoS攻撃対策などで重要な設定。

mod_authz_core/mod_authz_hostがコアモジュール。mod_rewriteも関係ある。

基本構文は以下。

Require host <address>
Require ip <ip address>

1番目の形式はドメイン名。2番目はIPアドレス。部分マッチする。マッチしたもののアクセスを許可する。

Requireの直後にnotを指定してアクセス禁止にできる。こちらが重要。

mod_cgi

mod_cgi - Apache HTTP Server Version 2.4

CGIプロトコルのApacheモジュール。cgi-scriptにハンドラーを割り当てるとCGIとして扱う。

mod_fcgid

mod_fcgid - Apache HTTP Server Version 2.5

FastCGIプロトコルのApacheモジュール。AddHandlerかSetHandlerでfcgid-scriptハンドラーに割り当てられると、FastCGIとして処理される。

プログラム側もFastCGIに対応している必要がある。

Error

sudo systemctl status apache2
● apache2.service - The Apache HTTP Server
     Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
    Drop-In: /etc/systemd/system/apache2.service.d
             └─privatetmp.conf
     Active: failed (Result: exit-code) since Fri 2024-12-06 15:09:28 JST; 12s ago
       Docs: https://httpd.apache.org/docs/2.4/
    Process: 38461 ExecStart=/usr/sbin/apachectl start (code=exited, status=1/FAILURE)

Dec 06 15:09:28 z-ken-senoo apachectl[38464]: AH00548: NameVirtualHost has no effect and will be removed in the next release /etc/apache2/ports.conf:8
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: [Fri Dec 06 15:09:28.259153 2024] [core:warn] [pid 38464] AH00117: Ignoring deprecated use of DefaultType in line 122 of /etc/apache2/apache2.conf.
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: AH00112: Warning: DocumentRoot [/home/gree/frontend/greenet/htdocs_net] does not exist
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: AH00526: Syntax error on line 7 of /etc/apache2/conf-available/rewrite-greenet.conf:
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: RewriteRule: unknown flag 'UnsafeAllow3F'
Dec 06 15:09:28 z-ken-senoo apachectl[38461]: Action 'start' failed.
Dec 06 15:09:28 z-ken-senoo apachectl[38461]: The Apache error log may have more information.
Dec 06 15:09:28 z-ken-senoo systemd[1]: apache2.service: Control process exited, code=exited, status=1/FAILURE
Dec 06 15:09:28 z-ken-senoo systemd[1]: apache2.service: Failed with result 'exit-code'.
Dec 06 15:09:28 z-ken-senoo systemd[1]: Failed to start The Apache HTTP Server.
AH00548: NameVirtualHost has no effect and will be removed in the next release /etc/apache2/ports.conf:8

NameVirtualHost指令が廃止予定なので、行を削除して対応する。

AH00117: Ignoring deprecated use of DefaultType in line 122 of /etc/apache2/apache2.conf.

DefaultTypeはnone以外意味がなく、警告表示になる模様。

.htaccess

directive

.htaccessで使用可能な指令一覧 – senooken JP

.htaccessで使用不能なよく登場して誤解する指令を整理しておく。

  • Alias
  • ScriptAlias
  • Directory/DirectoryMatch
  • Location/LocationMatch

逆にOKなもの。

  • Files/FilesMatch

E-mail

[サーバーIPがブラックリストに載ってメール送信エラーになるのを解除する方法]

MailHog: Go言語製のメールサーバーソフト。

Debian

PHP8

[How To Install PHP 8.0 on Debian 11/10/9 | ComputingForGeeks](https://computingforgeeks.com/how-to-install-php-on-debian-linux/)

Debian 11の場合、PHP 8には外部リポジトリーが必要なので追加する。

sudo apt update

sudo apt install -y lsb-release ca-certificates apt-transport-https software-properties-common gnupg2

PHPパッケージを追加する。

echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/sury-php.list

wget -qO - https://packages.sury.org/php/apt.gpg | sudo apt-key add -

sudo apt update

これでPHP8を参照できるので、インストールする。

sudo apt install php8.2

[How to Switch between Multiple PHP Version on Debian 12/11/10 – TecAdmin](https://tecadmin.net/switch-between-multiple-php-version-on-debian/)

インストールしたら、PHPのバージョンを切り替える。

a2dismod php7.4

a2enmod php8.2

sudo systemctl restart apache2

php 8.2にするとこういうエラー。

[Sat Sep 02 11:31:02.558029 2023] [php:error] [pid 25644] [client 133.106.38.37:57181] PHP Fatal error:  Uncaught Error: Undefined constant "DB_DATAOBJECT_ERROR_NODATA" in /var/www/gnusocial/public/index.php:104\nStack trace:\n#0 [internal function]: handleError()\n#1 {main}\n  thrown in /var/www/gnusocial/public/index.php on line 104

念のためdockerで起動を試みましたが、同じくトップ画面を開くと同じエラーになります。

<https://notabug.org/gnusocialjp/gnusocial/src/main/docker/development> にDockerでの起動方法があります。`docker compose up -d` を実行するだけでlocalhostでアクセスできます。

私とあなたとの環境の違いを排除したいので、dockerのインストールだけ頑張って、それでdockerでも簡単に動作確認してくれませんか?

alternative

Ref: DebianAlternatives - Debian Wiki.

OS内でバージョン違いのプログラムを管理するための仕組みがある。それがupdate-alternativesコマンド。

sudo update-alternatives --display vi
sudo update-alternatives --config vi

オプションとコマンド名を指定することで、現在の実体と更新ができる。

XAMPP

ポート番号変更

Xamppでポート競合を防ぐ方法 #PHP - Qiita

XAMPP Control PanelのConfigから変更可能。

phpmyadminはConfigのphpmyadminで、Servers.portを追加する。

Vim

Other

Async

https:/github.com/skywind3000/asyncrun.vim

asyncrun.vimは1個のバックグラウンド処理しか対応していない。

https://github.com/skywind3000/asyncrun.vim/issues/12

vim-dispatchならいけるのか?

Binary

vim-jp » Hack #133: バイナリファイルを編集する

grep

非同期でgrepする方法。

https://superuser.com/questions/861783/how-to-run-a-grep-in-vim-asynchronously

https://www.reddit.com/r/vim/comments/5ses2e/async_grep_in_vim_8/

Vim 8の非同期APIはプラグイン用。

* https://github.com/mhinz/vim-grepper

* https://github.com/skywind3000/asyncrun.vim

* https://github.com/tpope/vim-dispatch

https://wonderwall.hatenablog.com/entry/2017/10/09/210000

asyncrun.vimでやるのがよさそう。

AnsiEsc

* https:/unix.stackexchange.com/questions/444226/how-to-make-vim-interpret-escaped-characters-as-colors

* https:/superuser.com/questions/358409/how-can-i-tell-vim-to-show-ansi-escape-codes-properly

本家は太字に対応していないのでこちらがいいかな。

- https:/github.com/powerman/vim-plugin-AnsiEsc

ただし、こちらはgvimでクリック時にカーソル位置がずれる。

program

C

ワシのVimプラグインは百八式まであるぞ - daisuzu's notes

【C/C++】

     87. a.vim

        C/C++のヘッダとソースを切り替えます。

     88. c.vim

        C/C++のテンプレートやイディオムの入力をサポートしてくれます。

     89. CCTree

        cscopeを使って関数のコールグラフを表示してくれます。

     90. Source-Explorer-srcexpl.vim

        ソース解析ツール、Source InsightのVim版です。

     91. trinity.vim

        taglist, srcexpl, nerdtreeを同時に起動して

        VimがIDE画面のような画面になります。

     92. cscope-menu

        cscope用のメニューを表示してくれます。

     93. gtags.vim

        gtagsを使ってファイルを開けます。

     94. DoxygenToolkit.vim

        Doxygenコメントの入力をサポートしてくれます。

Visual Studio Code

Keybind

矩形選択

Ref: VS Codeの矩形選択と矩形貼付の操作方法 - mito’s blog.

  • s-alt-クリック
  • c-s-alt-矢印

ジャンプ

  • 括弧ジャンプ: C-S-\

Config

Default terminal

Ref: bash - Change the default terminal in Visual Studio Code - Stack Overflow.

[F1]-[Terminal: Select Default Profile]

cscope

cscope用のプラグインが何個かある。

scope4codeのほうがいろいろできそうだが、うまく動作しなかった。使い方がよくわからない。

cscope-codeはシンプルだが動作した。こちらを当分使うことにする。

Macの場合、control-. sのように、control-.の後に、controlを話してsを押すと発動する。カーソル下のシンボルしか使えない感じなのがネック。まあいい。

Vim

VSCodedでVimのキー操作を使うためのプラグイン。これが一番人気。いや、Vimのエミューレーターは中途半端な感じだから使わないほうがいいかな。

Extension

CSS

Tailwind CSS IntelliSense

PHP

Laravel Blade Snippets

PHP Intelephense

Ref: PHP Intelephense - Visual Studio Marketplace.

VSCodeのPHPの補完拡張として人気が高い。

Quick Start

設置後、しておくべき設定がある。

  • Go to Extensions.
  • Search for @builtin php
  • Disable PHP Language Features. Leave PHP Language Basics enabled for syntax highlighting.

VSCodeの [PHP Language Features] を無効にしておくとのこと。

後は、.php以外の拡張子でPHPファイルがあれば、関連付けを追加するとか。

Module

peclなどPHPの標準モジュールで一部認識できないものがある。

php - Undefined type 'Imagick' in VSCode's intelephense - Stack Overflow」にあるように、そういう場合は [Settings]-[Stubs] で追加するとよい。

Coding

Ref: VSCode で PHP 開発するならインテリセンス最強の intelephense を使おう | 株式会社ビヨンド.

intelephenseでコード補完を認識しやすい書き方というのがある。

まず、型をつけられるものはつける。

function superMethod()
{
    /** @var AwesomeService $awesomeService */
    $awesomeService = $this->app->make(AwesomeService::class);
    $awesomeService->awesomeMethod();
}

ローカル変数も型名を指定する。これをしないと、インスタンスでコード補完が効かない。

Other

Remote

【WinSCPはもう不要?】VS Codeのダウンロード/アップロード機能が便利すぎる!! | マスクロドットコム

Visual Studio Code Remote Development

公式拡張機能のVS Code Remote Developmentを使うと、リモートファイルをVS Codeで開いて、ドラッグドロップでファイル送受信ができるらしい。

PhpStorm

Encoding

パス単位で文字エンコーディングを設定可能。

[PhpStorm]-[Settings]-[Editor]-[File Encodings] から行う。

Scratch

【New Year Calendar】君はPhpStormのScratch機能を知っているか #NewYearCalendar - Qiita

メモなどの一時ファイルの作成機能。

[File]-[New Scratch File] からファイル形式を選んで作る。困ったらMarkdownで良いだろう。

作成したScratchファイルは [Project]-[Scratches and Consoles]-[Scratches] に格納される。

矩形選択

複数のカーソルと選択範囲 | PhpStorm ドキュメント

方法がいくつかある。

  • Cmd-Shift-8
  • Option-Shift-Middle

Git

Gitツールウィンドウ

C-9か左下のGitマークを選ぶとGitツールウィンドウの表示になる。ブランチとコミットログが表示される。ここから右クリックを使ってブランチ間の比較などができたりする。

ブランチ比較

コードレビューなどでよく使うブランチ同士の比較。

まず現在ブランチを比較対象ブランチに変更しておく。

[Git]-[Branches]-比較対象ブランチ-[Compare with]

これで上下に画面分割して、それぞれのブランチで固有のコミットログの一覧が表示される。派生元と派生先があるならば、片方が空になる。違うブランチ同士のマージ用に、こういう作りになっていると思われる。

差分ファイル一覧を見るには、右側の変更ファイルペーンでC-aを選ぶ。変更のある全ファイルのリストが表示される。

他に、Gitツールウィンドウを開いて、コミットログで右クリック-[Compare with Local]を選ぶとローカルと対象コミットとの比較になる。これがわかりやすい。

ただ、基本は現在ブランチか、現在のワーキングツリーとの比較になる。現在ブランチを変更しておくのが基本になる。そこだけ押さえておけば、まあなんとか使えそう。

Other

Window

プロジェクトを開く、移動、閉じる | PhpStorm ドキュメント

ペーンを分離したり移動したりできる。

ペーン右上[…]-[View Mode]-[Window] を選ぶと、別画面に分離できる。並列時に重宝する。

PIM

Personal Information Manager - Wikipedia

PIMという個人情報管理用アプリの分類がある。

  • カレンダー
  • アドレス帳
  • 電子メール
  • タスク管理
  • メモ帳
  • 音声メモ
  • 電卓
  • 時計
  • 電子辞書

E-mail

General

winmail.dat

winmail.dat変換ツール(インストール不要)

MS outlookなどで使われる添付ファイルの形式。

Naming
RFC
  • webmaster
  • support
  • info
  • service
  • pr
  • billing
  • 氏名

売上をアップするメールアドレス、商機を失うメールアドレス | マイナビニュース

infoやwebmasterなど企業サイトが備えるべきメールボックスのルール、ご存じですか? | 編集長ブログ―安田英久 | Web担当者Forum

rfc-jp.nic.ad.jp/rfc-jp/RFC2142-JP.txt

SuperTAINS News No.23 [Page.5]

【Mail】メールアドレス作成のガイドライン(RFC2142) – fumidzuki

公開用のメールアドレス。何にしようか考えていた。

RFC 2142でいくつか推奨されている。

info@ support@ answer@ inquery@ contact@ pubic@

contact@がやっぱり一番しっくりくる。info@ support@はRFC 2142にあるけど,これはビジネスより,サービスに紐付いたもの。個人でやる分にはサービス関係ないから,これは違う。publicも悪くはないのだけど,あまり一般的ではないか。

develop

GNU social JP管理人 (gnusocialjp@gnusocial.jp)'s status on Saturday, 08-Oct-2022 23:13:28 JSTGNU social JP管理人GNU social JP管理人
使用するメールアドレスに悩みます。GitのメールアドレスはGitのホスティングサービスに掲載され一般公開されます。

メーリングリストのメールアドレスも、返信方法によって引用されアーカイブで一般公開されます。

どう使い分けるのがよいでしょうか?案↓
GNU social JP管理人 (gnusocialjp@gnusocial.jp)'s status on Saturday, 08-Oct-2022 23:20:04 JSTGNU social JP管理人GNU social JP管理人
  1. develop@domainのようなアドレスで共有
  2. develop@, ml@ で用途別
  3. contact@ で一般公開用で共有
開発用のメールなので、1がいいですかね。仮に漏洩しても開発関係経由というのがわかるので。

1がいいと思う。

category

目的に応じて使い分けたほうがよさそう。

メールアドレスを何個ぐらい使い分けたら安全・快適に過ごせるのか - Dr.ウーパのコンピュータ備忘録

メールアドレス流出時の被害防止

不審なメールの検知

必要な数

  • 銀行・証券会社
  • 知り合い
  • ショッピングサイト

その他

  • Webサイトなどの公開用
  • 本名でのやり取り
  • ニックネーム
  • 金銭のやり取りのないサービス登録
  • 金銭のやり取りのあるサービス登録
  • 登録にメールアドレスが必要だけど,そんなに使っていないメール

メールアドレスの種類

  • フリーメール
  • プロバイダーメール
  • 独自ドメイン

メールアドレスの種類とアフィリエイトにおける3つの使い分け方法 | アフィリエイト

  • サービス登録用
  • メルマガ購読用(捨てアド)
  • メインアドレス

メールアドレスの使い分けかた(前編) - 学習する機械、学習しない人間

メールアドレスの使い分けかた(後編) - 学習する機械、学習しない人間

これらを考えてどういう名前で何個用意するかを考える。

とりあえずメインで使うmainというアドレスを一つ用意する。残りをどうするか。

Webサイト公開用にcontact

  • main: メインで使うメール。人に直接教えるときや,お金が絡む場合,ショッピングサイトなど実名が求められるような重要な内容にはこれ。こちらから送信するときもこれ。相手の顔が見えているとき。
  • contact:受信専用,公開用。問い合わせ用。なんかフォーラムやブログのコメント欄やcontact usなどにこちらから問い合わせる時なども。相手の顔が見えないときなど。
  • service: 基本的に受信専用,たまに返信。Webサービス登録用。
  • recruit:就職活動用。就職サイトとか転職エージェント,企業とやりとりするときはけっこうメール来るから。
  • job: 個人事業、仕事用、不動産は事業なのでこちら。
  • money: 金融機関登録用。銀行、証券会社、クレジットカード会社、決済会社・サービス。
  • shop/store: ショッピングサイト、個人間売買サイト。
  • ユーザー名: メールアドレスの@以前はユーザー名とみなされることがあるので、ユーザー名のアドレスも用意しておくとよさそうだ。


こちらから送信するときのメールアドレス。

Webサービスに登録するときどうするか。不動産屋さんとか人に教えるときはどうするか。アフィリエイトとかドメインとか実名が求められるときはどうするか。

gmailの+を考える。gmailでは+や.をつけると無限にアドレスをつけられる。ただし,受信は+のないメール。

ただし,gmailの+は使えないときがある。@以前の部分をユーザー名とみなして,+を無効な文字とみなすサービスがある模様。

ネットではがきが印刷~郵送できるポスコミ【1枚から注文OK】

https://www.tomtop.com/もだめ。

今まで使ってきたメールとはどうやりくりするか。

Thunderbirdでやる場合,Archiveするときに既読とメールのコピーを行う。

他のアドレスのメールはmainに転送するようにしておいて,mainのメールアドレスで確認。

最終的にThunderbirdでArchiveを実行したら,宛先のメールのフォルダーに同じ内容が既読状態でコピーされることにする。

このようなフィルターを作っておく。受信時にコピーしてしまうと,未読状態でコピーされてしまうか,受信した瞬間に既読状態になってしまい,見逃す可能性が高い。

Manage Identitiesで返信時に受信したアドレスで返信できるように登録しておく。

Mozilla Thunderbird

プロファイルの統合

ImportExportToolsでデータ移行するというのが手堅い。一括操作を念頭に置いた機能になっている。数が少ないならば、emlファイルをドラッグドロップで取り込むこともできる。