そーくのつれづれぶろぐ

web系エンジニアの勉強したことなど

【Postgresql】オブジェクト識別子データ型とは ~C言語のint→charのキャストみたいなもの~【メモ】

前提

  • postgresqlはユーザ/システムが作ったDB関連の部品を'オブジェクト'として管理する
  • データベースクラスタ/スキーマ/テーブル/インデックス/シーケンス/データ型etc
  • 管理するので何かしらの情報をまとめる→postgresqlの世界では「システムカタログ」という(あとでざっくり図解を公開する)
  • オブジェクトにはすべて一意のIDをふる → oid
  • オブジェクト識別子 = oid
  • オブジェクト識別子は数値(10進数なはず)

oidに触れる機会の例

  • テーブルの特定カラムのデータ量が多すぎたらアラートメールを投げるようにする
  • 該当のテーブルがあればデータを取得する

↑の情報を取得するのにシステムで管理しているテーブルをオブジェクト識別子で結合しまくる必要があるが、 ユーザ側からみたらとってもみづらいSQLになる...

→そこで「オブジェクト識別子データ型」

オブジェクト識別子データ型

  • データ型
  • C言語のchar/intのキャストと同じイメージ
(int)'A';  // 65

char型「A」をintでキャストして「65」になるように、

'sales':: regclass

regclassというオブジェクト識別子データ型でキャストして「oid」になる便利なやつでした。

雑感

過去にやった言語のイメージがあったおかげで今回の記憶定着に役立った。
経験って大事。

参考URL

いつもお世話になっています。
lets.postgresql.jp

【PHP】ゆるやかな比較(==)は4ポイント覚えたらマスターできた

動機

https://www.php.net/manual/ja/types.comparisons.php

PHP特有の"ゆるやかな比較"を利用した書き方は簡便にかけるし可読性が高くてよい反面、思わぬ不具合の原因であったり日々の実装で思うように動かないときの原因にも結構なりえるので結構このページを参照している。

文字列→数値変換でハマったのをきっかけに今一度上記の表を眺め見ていたけれども、数点のポイントを覚えておけばあとはその場で考えてぱっと思い出せるなと気づいたため、忘れないうちに書き残すことにする。

覚えておくべき4ポイント

  1. NULLはFALSEと同義
  2. 空はFALSEと同義
  3. 0はFALSEと同義
  4. 式の中にstringと数値が両方存在している場合はstringが数値型に評価されてから比較される
    • stringの数値変換ルールは↓にまとめてます

soachr.hatenablog.com

雑感

入門書では1,2,3は言及されていた(3ヶ月前くらいに読んでいた)。JavaからのPHPだったため記憶に残ったのかもしれない。なのであとは文字列、数値の曖昧さを潰したらほぼほぼ大丈夫だったというのに過去記事を書き終わってから知った。 数値を文字列に変換は特に問題はないはずだからこれで実装時でハマることはなくなった気がする。よし。

【PHP】文字列から数値への変換法則をわかりやすく表してみた(PHPコードwith正規表現)

概要

PHPの本家に書いてあるけれども、文字列→数値の変換ルールを文字だけで説明されてるとすぐに頭に入らないので、擬似コードにした。 https://www.php.net/manual/ja/language.types.type-juggling.php

動機

直接的な動機ではないけれどもヒヤリハットとして頭に入れておいて損はしないだろうと思い記事を書くことにした。

脆弱性ツールによって開発中の画面にXSSが見つけられたので、その対応をすることになった。修正前に一度XSSを発生させよーとXSSを発生させる手順を踏んだはずが、なぜか発生しない事象に出会った。

少し掘り下げて書くと、整数を想定しているhiddenパラメータに悪意のある文字列(alert();だとか)を入れてsubmitすると実行されるという内容だった。そのためXSSを発生させるような入力値をいれてさあ脆弱性でてきてくれ!とsubmitをするが発生しない。なぜだ。といろいろ入力値を変えていたら発生する場合と発生しない場合があるというのが明らかになった。

発生しない場合というのが、その入力値がalert(123);というように数値が途中で入っていたときだった。おそらくフレームワークがフォーム値にバリデートをかけるときに数値が入っていれば数値に変換し、入っていなければ数値変換しない処理を入れているらしくXSSが発生しない、という内容だった。(逆に文字列onlyだったら通るのはフレームワークの不具合ではと思ったがとりあえずここでは割愛する)

PHP特有の「あいまいな表現でもOK」が仇となる場合もままあることと、webアプリの特性として「フォーム値(文字列)を数値として読む」ことは避けられないため、今後実装をする場合に考慮に入れることはそうとして一度整理していざというときにすぐに分かる形にまとめたいと思ったためここに記載する。

文字列から数値への変換法則をPHPプログラムで表現する

前置きが長くなったが、文字列からの数値への変換法則を書いてみる。

$VALID_NUM_PATTERNがいかんせんややこしい正規表現書いているけれどここで本家サイトの引用をば。以下の文章を正規表現で表した次第。

有効な数値データは符号(オプション)の後に、 1 つ以上の数字 (オプションとして小数点を 1 つ含む)、 オプションとして指数部が続きます。指数部は 'e' または 'E' の後に 1 つ以上の数字が続く形式です。

<?php

function convertStr2Num(string $str) {
  $VALID_NUM_PATTERN = '[-+]?[0-9]+([\.][0-9]+)?([e|E][0-9]+)?';
  $pattern = '/^(' . $VALID_NUM_PATTERN . ')/';
  
  // 1. 有効な数値データが文字列の0文字目から存在するか
  if (preg_match($pattern , $str, $matches)) {
    // 2. 小数点がない、指数部がない、integerの最大値より小さい 
    if ((strpos($matches[0], '.') === false) && 
        (strpos($matches[0], 'e') === false) &&
        (strpos($matches[0], 'E') === false) &&
          strlen($matches[0]) < PHP_INT_MAX) {
      return (integer)$matches[0];
    } else {
      return (float)$matches[0];
    }
  } else {
    return (int)0;
  }
}

終わりに

まとめるとこう↓

「整数じゃない値が文字列の最初に来ていたらfloat, 整数が文字列の最初に来ていたらinteger、それ以外は全部(integer)0」

書いている途中からこの1文がすべてと気づいてしまってちょっと消え去りたくなった。 私の正規表現記述能力が向上したのと、コード書かないと書くスピードが上がらないことを実感したから個人としては、有益、だったと...いうことで...

【PHP】【メモ】暗黙的型変換がされる四則演算について("10.0hoge" + 1 の結果は何か)

以下のように演算がなされる

  1. オペランドを数値型に変換
  2. オペランドいづれかがfloatであれば、すべてのオペランドがfloatで評価された後、演算がなされ結果もfloatになる 1
$ php -a
Interactive shell

php > var_dump("10.0hoge" + 2);
PHP Notice:  A non well formed numeric value encountered in php shell code on line 1
float(12)
php > var_dump("10.0hoge" - 2);
PHP Notice:  A non well formed numeric value encountered in php shell code on line 1
float(8)
php > var_dump("10.0hoge" / 2);
PHP Notice:  A non well formed numeric value encountered in php shell code on line 1
float(5)
php > var_dump("10.0hoge" * 2);
PHP Notice:  A non well formed numeric value encountered in php shell code on line 1
float(20)

雑感

オペランドを数値型に変換

ここについては別記事で記載する

【PHP7】関数の引数のデフォルト値の振る舞いを見てみる

動機

JavaからPHPを学び始めたが、Javaの感覚で書くと言語仕様(理解不足)による不具合を生み出しそうという感覚があるため、入門書を読みながら挙動を確認している。学んでいる中でJavaと違う点として、引数にデフォルト値が設定できるとのことなので、デフォルト値を設定有無×関数呼び出し時の引数の数のバリエーションを試してみた。

結論

  • 関数に渡した引数の数 < デフォルト値を設定していない引数の数 の場合はFatal Errorになり後続処理は実行されない
  • 少なくとも引数の一番最後以外にデフォルト値を設定しても、設定していないのと同じ挙動になる
    • func($num1, $num2) イコール func($num1=5, $num2)

(あと今回とは話がそれるが、関数に渡した引数の数 > 関数定義で指定した引数の数 の場合は余剰分の引数は無視される)

ソース

<?php

function variable_1($msg) {
    print "variable_1: {$msg}<br/>";
}
function variable_1_op($msg="default") {
    print "variable_1_op: {$msg} <br/>";
}

function variable_2($msg1, $msg2) {
    print "variable_2: \$msg1: {$msg1} and msg2: {$msg2}<br/>";
}
function variable_2_op_1st($msg1="default1", $msg2) {
    print "variable_2_op_1st: \$msg1: {$msg1} and msg2: {$msg2}<br/>";
}
function variable_2_op_2nd($msg1, $msg2="default2") {
    print "variable_2_op_2st: \$msg1: {$msg1} and msg2: {$msg2}<br/>";
}
function variable_2_op_both($msg1="default1", $msg2="default2") {
    print "variable_2_op_both: \$msg1: {$msg1} and msg2: {$msg2}<br/>";
}

function variable_3_op_2nd($msg1, $msg2="default2", $msg3) {
    print "variable_2_op_2st: \$msg1: {$msg1} and msg2: {$msg2} and msg3: {$msg3}<br/>";
}

print "***********引数が1つの場合***********<br/>";
variable_1('msg');
//  variable_1(); // Fatal error: Uncaught ArgumentCountError: Too few arguments to function
variable_1_op('msg');
variable_1_op(); //defalt

print "***********引数が2つの場合***********<br/>";
print "***デフォルト設定なしのとき<br/>";
// variable_2(); //Fatal error: Uncaught ArgumentCountError: Too few arguments to function
// variable_2('msg1'); //Fatal error: Uncaught ArgumentCountError: Too few arguments to function
variable_2('msg1','msg2');
print "***デフォルトが第一引数に設定されているとき<br/>";
// variable_2_op_1st(); // Fatal error: Uncaught ArgumentCountError: Too few arguments to function
// variable_2_op_1st('msg1'); // Fatal error: Uncaught ArgumentCountError: Too few arguments to function
variable_2_op_1st('msg1','msg2');
print "***デフォルトが第二引数に設定されているとき<br/>";
// variable_2_op_2nd(); // Fatal error: Uncaught ArgumentCountError: Too few arguments to function
variable_2_op_2nd('msg1');
variable_2_op_2nd('msg1','msg2');
print "***デフォルトが両引数に設定されているとき<br/>";
variable_2_op_both();
variable_2_op_both('msg1');
variable_2_op_both('msg1','msg2');

print "***********引数が3つの場合***********<br/>";
print "***デフォルトが第二引数に設定されているとき<br/>";
variable_3_op_2nd('$msg1','$msg3'); //Fatal error: Uncaught ArgumentCountError: Too few arguments to function

雑感

C言語っぽさがでていて割とすんなりと挙動が頭に入った。(学生時代はC言語をやっていた)PHPC言語から作られていることを思い出させる内容だった。

【PHP】グローバル変数の呼び出しでタイポしたときの挙動

動機

既に定義されているグローバル変数を関数内で呼び出す、となると、 もしタイポして定義されていないグローバル変数を参照しようとしてたら...PHPだともしやエラーとかでないのでは?と思って調べる。

  • 確認環境 : PHP7.3.6

結論

warning/errorともに出ず、NULLとなる

挙動

<?php

$gMsg = 'global variable';
use_global_keyword();
use_GLOBALES_array();

function use_global_keyword() {
    print 'use_global_keyword<br/>';
    global $gMsg;
    print "$gMsg<br/>";
    global $notDefined;
    print "定義されていない変数を呼び出す:{$notDefined}<br/>";
    var_dump($notDefined);
}

function use_GLOBALES_array() {
    print 'use_GLOBALES_array<br/>';
    print "{$GLOBALS['gMsg']}<br/>";
    print "定義されていない変数を呼び出す:{$GLOBALS['notDefined']}<br/>";
    var_dump($GLOBALS['notDefined']);   
}

実行結果

use_global_keyword
global variable
定義されていない変数を呼び出す:
NULL use_GLOBALES_array
global variable
定義されていない変数を呼び出す:
NULL

雑感

Javaから入った人間としてはPHPはいろいろゆるくてびっくりする。
Javaではコンパイルエラーなところがwarningだけで止まらない。場合によっては言語仕様によってwarningすら出ない。 今後判定条件を記述する際はあまり手を抜かずに厳密にやるようにする(そもそもそういうのを考えないようするための言語仕様な気がするが...

【メモ】Macでapache+php環境の構築(phpinfo()表示まで)

ゴール

PHPほぼ未学習なので、生のPHPでのwebアプリプログラミングでPHPに慣れる、ための環境を準備する

環境

  • macOS Mojava 10.14.5
    • (おそらくプリインストールされてる)php7系
    • (おそらくプリインストールされてる)apache

手順

だいぶ自信はないが、別途拡張モジュールをDLする作業は必要はない。 apacheの拡張モジュール(libphp7.so)もすでにDL済でかつ、apache.confコメントアウトでロード文が用意されている。 初学者にはありがたい。

  1. apache.confに以下内容を記述
  2. apachephpを実行させる拡張モジュールをロードする(LoadModule php7_module [path])
  3. ルートアクセス時のデフォルトページを設定(DirectoryIndex)
  4. MIMEphpを登録(AddType application/x-httpd-php .php)
  5. php.iniの場所を指定(PHPINIDir)
  6. (任意)ルートディレクトリ設定

  7. apacheを再起動(sudo apachectl restart)

  8. ルートディレクトリにphpinfo()を記載したphpファイル(phpinfo.php)を作成
  9. http://localhost/phpinfo.phpにアクセス
  10. phpinfo表示される!

雑感

  • サーバ起動スクリプトはいつもCentOS6系の/etc/init.d/*でやっていたのでapachectlほぼ初めてで少し新鮮だった(CentOS7はよなれておかないと...とも思った)
  • 設定ファイルどこかわからなくて探すのに時間がかかった
    • httpd.conf ... /etc/apache2/httpd.conf
    • php.ini ... /etc/php.ini.defaultphp.iniはいなかったので左記をコピペして作成。*php環境変数のパス情報はphp -iでわかる**のでこのコマンドを覚えていたら汎用性高いし良さそう
  • mac標準インストールのhttpdの設定ファイルや拡張モジュールなどの/sbin:/bin実行プログラム以外のものは基本的にUnix系共通の、/etc/にいたはいたが、サーバを再起動したりすると/private/という基本的に書き込みできないディレクトリにコピーされて、そのコピーしたやつで実行する、というようにして直接いじらないようにしているようだった。それをする理由がよくわからず腑に落ちない。低レイヤはなるべくユーザに使わせたくないっていうMacのあれなのか。
  • 1年前くらいに下の本を読んでいたのが今回大きかった。設定ファイルをいじるのに未知への漠然とした不安がないのはよかった。この本読み返したいな...でも今じゃないな
  • postgresの設定は次のときにやろう

参考