ラベル php の投稿を表示しています。 すべての投稿を表示
ラベル php の投稿を表示しています。 すべての投稿を表示

2019/12/12

土日・祝祭日をカウントしないクエリ

土日、祝祭日をカウントしないで、経過日数から処理を行いたい。

休日テーブルのようなものを作って、LEFTJOINして加工
のようなことをやっていたが、
DBなくても動くものが欲しかったので、調べてみたオボエガキ。

範囲を絞る方法として、
次のように使う

select 【id】 from 【table名】
where (to_timestamp(to_char(now(),'YYYY-MM-DD'),'YYYY-MM-DD') -
(to_timestamp(to_char(【table名】.【受付日】,'9999-99-99'),'YYYY-MM-DD'))) > interval '5 days'
and
 (SELECT count(*) FROM generate_series(to_timestamp(to_char(【table名】.【受付日】,'9999-99-99'),'YYYY-MM-DD'),
to_timestamp(to_char(now(),'YYYY-MM-DD'),'YYYY-MM-DD')-interval  '1 day',
interval  '1 day') the_day
WHERE (extract('ISODOW' FROM the_day) < 6
and not(EXTRACT(MONTH FROM the_day) * 100
+ EXTRACT(DAY FROM the_day)
IN (101, 113, 211, 223, 224, 320, 429, 503, 504, 505, 506, 723, 724, 810, 921, 922, 1103, 1123) ) ) ) >4

idが 【table名】.【受付日】から5日以上経過(当日含まないので中4日)
なお、条件として、【table名】.【受付日】がint2(8)の為、DATE型に変換している。

解説
副問い合わせをしているのだが、

(SELECT count(*) FROM generate_series(to_timestamp(to_char(【table名】.【受付日】,'9999-99-99'),'YYYY-MM-DD'),
to_timestamp(to_char(now(),'YYYY-MM-DD'),'YYYY-MM-DD')-interval  '1 day',
interval  '1 day') the_day
WHERE (extract('ISODOW' FROM the_day) < 6
and not(EXTRACT(MONTH FROM the_day) * 100
+ EXTRACT(DAY FROM the_day)
IN (101, 113, 211, 223, 224, 320, 429, 503, 504, 505, 506, 723, 724, 810, 921, 922, 1103, 1123) ) ) ) >4

 generate_series という集合を返す関数を使って、カウントが中4日となる様に制御している。

 generate_series
(
to_timestamp(to_char(【table名】.【受付日】,'9999-99-99'),'YYYY-MM-DD'),
to_timestamp(to_char(now(),'YYYY-MM-DD'),'YYYY-MM-DD')-interval  '1 day',
interval  '1 day'
) the_day

始まり,終わり,間隔 と記載している。 
終わりの中で -interval  '1 day' としているのは、当日を入れたくないため。

WHERE
(
extract('ISODOW' FROM the_day) < 6
and not
(
EXTRACT(MONTH FROM the_day) * 100
+
EXTRACT(DAY FROM the_day)
IN
 (101, 113, 211, 223, 224, 320, 429, 503, 504, 505, 506, 723, 724, 810, 921, 922, 1103, 1123)
)

extract('ISODOW' FROM the_day) < 6 ISODOWは6が土曜、7が日曜となる。
(DOWだと0が日曜、6が土曜)

and not 以下の括りで、国民の休日をカウント対象から除外させている。

EXTRACT(MONTH FROM the_day) * 100
+
EXTRACT(DAY FROM the_day)
で月を100倍し、日と足す。
これを 副問い合わせのIN関数
(左側の式の結果が右側の式のどれかと等しい場合、結果は「真」を返す)
を用いて、その日付だった場合は、2重否定となり、カウントされない。


固定日以外の春分の日なんかは、国立天文台の算定式で括ってあげればいいんだが、
このところ、天皇即位やオリンピックで変則が多いので、調べて直接日付を書いたほうが
よさそう。

春分の計算
(EXTRACT(MONTH FROM date) = 3
AND EXTRACT(DAY FROM date) = FLOOR(20.8431
+ 0.242194 * (EXTRACT(YEAR FROM date) - 1980))
- FLOOR((EXTRACT(YEAR FROM date) - 1980) / 4))



and not でそれぞれ括れば、除外できるが

and not が直ぐに思いつかなかった・・・。

2018/04/05

PHP URLのgetパラメータ で利用できる文字列と対策

メールで飛んできた内容にurlを張り付けて、DBに書き込むという
少々危険な匂いを漂わせるプログラムを書いたところ、

urlのgetパラメータにコード変換しないと利用できない文字列があった。

具体には以下の一覧を参照

文字 ! " # $ % & ' ( ) * + , - . /
コード %20 %21 %22 %23 %24 %25 %26 %27 %28 %29 %2A %2B %2C %2D %2E %2F
文字 : ; < = > ? @ [ \ ] ^ _ ` { | } ~
コード %3A %3B %3C %3D %3E %3F %40 %5B %5C %5D %5E %5F %60 %7B %7C %7D %7E

今回は、メールアドレスをgetパラメータで遣り取りしたかったので、
@を%40に変換してあげる必要がある。

$mailadd= "hoge@hoge.com";
$mailadd = str_replace("@", "%40", $mailadd);


$msg .= "http://192.168.0.xxx/insert.php?password=$password&username=$username&mailadd=$mailadd"."\n";

こんな感じで
メールの本文の中にinsert.php で使う変数をgetパラメータで予め投げておきたいときに
役に立ちそう。
地味に%20の半角や%2fのスラッシュあたりが便利。


2016/09/06

サーバ移転で詰まったこと php関連

WEBサーバを移転した際に、嵌ってしまった原因を列挙しておく。
次回の更新が何年後か分からないが、忘備録

PHPのこと

/etc/php.ini
phpが稼働したら、
info.phpファイルを作り、設定確認
infophp();
?>


memory_limit (メモリ使用量の上限)
post_max_size (POSTデータの最大サイズ ※1回のアップロードファイルすべての合計サイズ)
↑今回、これを確認せず、8MBの壁にぶち当たり嵌った・・。

upload_max_filesize  (1ファイルあたりの最大アップロードサイズ)

この辺の数値が小さいと、画面が白いままになったり、
IF関数等で正しく動かない。

反映は

 # systemctl restart httpd.service




Postfixのこと

設定されているサイズを確認

# postconf | grep size_limit

body_checks_size_limit = 51200
bounce_size_limit = 50000
header_size_limit = 102400
postconf: warning: /etc/postfix/main.cf: unused parameter: mtp_sasl_security_options=
mailbox_size_limit = 此処をでかくする      例えば1GB     1073741824
message_size_limit = 此処を↑は小さくする  例えば100MB 104857600

反映は

# systemctl restart postfix.service


phpで作ったメールフォームで嵌った。



2016/08/09

postfixの設定など

社員用にPHPプログラム運用兼ファイルサーバを設置している。
いままでは、ローカルなメールの遣り取りだけで済んでいたのだが
どうしても、外部のメールサーバを経由して外部ユーザにメールを送らないといけなくなった。

ローカルの設定は結構いい加減にやっており、
外部にメールを送ろうとすると、rejectされてしまう。

CentOS7.x はpostfixが推奨されているので、設定することにした。

はじめに
postfixが動いているか?確認




# systemctl status postfix.service

今回は、phpが絡むので、設定する。
/etc/php.ini
L980位の
[mail function]
SMTP = localhost
smtp_port = 25
sendmail_from = なんかそれなに名前を付けておく。

※SMTP認証を使うときは、もう少し追記があるらしい。(今回はいらない)

# systemctl restart httpd.service
PHPの設定有効


つづいてpostfixの設定

前のかなりラフなものをちゃんとする。

 /etc/postfix/main.cf

L60
mail_owner = postfix 別のユーザに変更するときは、書き換える(今回不要)

myhostname = mail.xxx.co.jp 等

mydomain = xxx.co.jp 等

inet_interfaces = localhost 受信設定。受信しないので、localhostで良いが、ルータ等でセキュア環境にしてあるならば、allでもOKと思われる。

inet_protocols = ipv4 おまじない。ipv6をkillしている際は、記載しないと動かないらしい。

mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain ←註

mynetworks = XXX.XXX.XXX.0/24, 127.0.0.0/8 許容するネットワークの範囲を記載


mydestination に $mydomain を記載する際の注意

内部用のサーバから外部用のサーバにリレーする際に、
内部的には固定IP割り当てて、ルータで締めて、トンネル作って、そのアドレスを許容すればいいのだが、そこから外部に送る際、最近のレンタルサーバ等は、domainがいい加減だと、rejectしてくる。

そこで、$mydomainには、送信する際に問い合わせを受けても問題ないdomainを記載しておくのだが、mydestination に $mydomain を安易に書き加えると、外部サーバと内部サーバに同一の
アカウントがいる場合は、そのユーザに関しては、ローカルサーバ内にメールを送ってしまい。
本来の$mydomain に送るべきものが全く送れない状態になってしまうので、
注意が必要。
外部サーバを使ってメールを送信するような内部サーバのpostfixの設定で、
よほど特殊(たとえば内部で擬似的に運用する等の)な環境でない限り、
記載する際は注意が必要。






※SMTP認証を使う場合は、この辺も有効にする。
# In the case of SMTP, specify a domain, host, host:port, [host]:port,
# [address] or [address]:port; the form [host] turns off MX lookups.
#
# If you're connected via UUCP, see also the default_transport parameter.
#
#relayhost = $mydomain
#relayhost = [gateway.my.domain]
#relayhost = [mailserver.isp.tld]
#relayhost = uucphost
#relayhost = [an.ip.add.ress]

その他はそのままで大丈夫と思われる。

# systemctl restart postfix.service
再起動
# systemctl status postfix.service
エラーが無いか確認する。



この設定で、問題なく中継が出来た。
今後Gmailやその他のメールサーバと絡めたりしたいときには、
SMTP認証が必要になる。(今は止めておく)




2016/07/08

PHP 複数行を持つ標準入力の配列化

複数行を持つ標準入力の配列化

 

<?php
$input = trim(fgets(STDIN));
while ($input){
$array[] = $input;
$input = trim(fgets(STDIN));
}



これで、$arrayに標準出力の複数行で書かれたものを

配列に出来る。




一列づつ検証をする場合は、

 

    while($input=fgets(STDIN)){
  for ($i = 1; $i <= $input-1 ; $i++) {

この中で検証する;

}


このように処理すれば良い。



スキルアップの為、codeIQとかで勉強を始めたが、

標準入力の取り扱い方が良くわからずに困っておった。

 

 

プログラム自体は掛けるのだが、

標準入力の配列化が出来ず、解けない問題があったので、

いろいろ調べた結果 こうなった。

2016/05/24

CentOS7 ssh2_connectを実装する

正規の方法でインストールを試みるが、

#pecl install ssh2
PHP Warning:  PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/msql.so' - /usr/lib64/php/modules/msql.so: cannot open shared object file: No                                                            
such file or directory in Unknown on line 0
PHP Warning:  Module 'mbstring' already loaded in Unknown on line 0
PHP Warning:  Module 'pgsql' already loaded in Unknown on line 0
Failed to download pecl/ssh2 within preferred state "stable", latest release is version 0.12, stability "beta", use "channel://pecl.php.net/ssh2-0.12" to install install failed

エラー

ネイティブな解説ページが有ったので、
参考にしながら実装までのオボエガキ


先ずは、yumを最新にする。

# yum update

# yum install make gcc libssh2 php-deve

# pecl install -f ssh2
PHP Warning:  PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/msql.so' - /usr/lib64/php/modules/msql.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning:  Module 'mbstring' already loaded in Unknown on line 0
PHP Warning:  Module 'pgsql' already loaded in Unknown on line 0
WARNING: failed to download pecl.php.net/ssh2 within preferred state "stable", will instead download version 0.12, stability "beta"
WARNING: channel "pecl.php.net" has updated its protocols, use "pecl channel-update pecl.php.net" to update
downloading ssh2-0.12.tgz ...
Starting to download ssh2-0.12.tgz (26,223 bytes)
.........done: 26,223 bytes
6 source files, building
running: phpize
Configuring for:
PHP Api Version:         20100412
Zend Module Api No:      20100525
Zend Extension Api No:   220100525
libssh2 prefix? [autodetect] :     ←ここはブランクのまま エンターした。
Build process completed successfully
Installing '/usr/lib64/php/modules/ssh2.so'
install ok: channel://pecl.php.net/ssh2-0.12
configuration option "php_ini" is not set to php.ini location
You should add "extension=ssh2.so" to php.ini

となるので、

# echo "extension=ssh2.so" > /etc/php.d/ssh2.ini

httpdを再起動させる。

# systemctl restart httpd.service

# php -m | grep ssh2
PHP Warning:  PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/msql.so' - /usr/lib64/php/modules/msql.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning:  Module 'mbstring' already loaded in Unknown on line 0
PHP Warning:  Module 'pgsql' already loaded in Unknown on line 0
ssh2

phpinfo() で確認すると

ssh2

SSH2 supportenabled
extension version 0.12
libssh2 version 1.4.3
banner SSH-2.0-libssh2_1.4.3

となり、実装完了。

実装方法




<?php
$connection = ssh2_connect('アドレス', 22);
ssh2_auth_password($connection, 'ログインユーザ名', 'ログインパスワード');

ssh2_scp_send($connection, '../転送元ファイル', '転送先ディレクトリ/転送するファイル', 0644);
?>

2015/07/09

CentOSからPHPを使って MicrosoftSqlServerに接続

CentOSからPHPを使ってMicrosoftSqlSeverに直接アクセスは出来ないらしく、

FreeTDSを使って橋渡しをするらしい。

イメージとしては、
PHP ⇔ FreeTDS ⇔ MsSqlServer
こんな感じの流れのようです。

とりあえず、FreeTDSでSqlServerにつかがるかを実験してみる。

先に unixODBCをインストールしている理由は、
FreeTDSはSybaseやSQL Serverと通信をするためのプロトコルであって(インターフェイス)、
DBへのアクセスをする場合にはODBCドライバを経由して行わなければならない。
らしい。
http://www.amy.hi-ho.ne.jp/jbaba/unix/tdsodbc.htm
↑ここに技術解説があった。みなさんここを見ているらしいです。

# yum install unixODBC-devel

ODBCドライバをインストール。

# yum install freetds-devel
FreeTDSをインストール。

freetdsにSqlServerの設定をする。
# nano /etc/freetds.conf

末尾に

[sqlserver]
host = DBサーバアドレス
port = 1433
tds version = 8.0
charset = sjis
client charset = utf-8
language = japanese

を加える。


charset は デフォルトはCP932だが、今回のベンダの設定では
SeqServerに定義したエンコードはsjisだったようだ。
エンコード関係でやはり30分ほど嵌った。


# tsql -S sqlserver -U ユーザ名 -P パスワード名
locale is "ja_JP.UTF-8"
locale charset is "UTF-8"
1>
となれば接続成功。

1>select * from テーブル名
2>go

このように使う。

ここまでが事前準備。



接続実験


$server=’DBサーバアドレス’;
$username='ユーザ名';
$password='パスワード';
$con=mssql_connect($server,$username,$password);

if($con !=FALSE)
{
        echo "Connection to SqlServer successful
";
}
else
{
        die("Connection to SqlServer failed");
}

mssql_close($con);
?>



次は、二つのDBを跨いだときの取り扱いを残す予定。

2014/12/02

pdfファイルに一括してパスワードを設定するため、PDFTkをインストール

複数のpdfファイルに一括してパスワードを設定する事が
かなりの頻度で必要になったので、
手持ちのacrobatで何とかしようと思ったが、
9のstandardしかなく、バッチ処理に対応していなかった。


しょうがないので、フリーのツールを探すと
pdftkがメジャーなようで記事がたくさんあるので、とりあえずインストールしてみる。


# wget https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/pdftk-2.02-1.i386.rpm
www.pdflabs.com の証明書(発行者: /C=US/O=DigiCert Inc/CN=DigiCert Secure Server CA)の検証に失敗しました:
  発行者の権限を検証できませんでした。
www.pdflabs.com に安全の確認をしないで接続するには、`--no-check-certificate' を使ってください。
SSL による接続が確立できません。


なるほど、
# wget --no-check-certificate https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/pdftk-2.02-1.i386.rpm


保存完了したので、
# yum install --nogpgcheck pdftk-2*
署名無いので、--nogpgcheck で署名なしのオプションつけないと蹴られる。


インストール後の使い方

変換前ファイル mae.pdf
変換後ファイル(任意名称) ato.pdf
スタンプ      stamp.pdf
印刷のみ許可のオプション owner_pw ***** allow printing

pdftk mae.pdf stamp stamp.pdf output ato.pdf owner_pw ***** allow printing

当初、指定のフォルダにファイルを置き、cronで5分間隔で実行すればいいだろうと
考えていたのだが、
利用者から、cronでの自動化だと操作した感が無く、忘れそうだとの事だったので、
今回は、スクリプトシェルにして、phpで動作させた。

++++++ソース converter.sh++++++

#!/bin/sh
# PDFコンバート&パスワード保護 スクリプトシェル
#
#作業  ディレクトリ /home/storage1/AAA/ConvertPdf
#変換後 ディレクトリ /home/storage1/AAA/ConvertedPdf
#スタンプ /home/storage1/AAA//ConvertPdf/sourse/stamp.pdf


cd /home/storage1/AAA/ConvertPdf
for file in *.pdf; do pdftk $file stamp ./sourse/stamp.pdf output /home/storage1/AAA/ConvertedPdf/`date '+%Y-%m-%d-%H%M%S'_`$file owner_pw **** allow printing; done
rm *.pdf


+++++++++++++++++++++++++++

作業内容
ConvertPdfにあるpdfにstamp.pdfをして印刷のみ許可の状態にしたファイルを
先頭に日付を付けてConvertedPdfにコピーし、
ConvertPdfにあるpdfファイルを削除する。

phpに関して
 phpを動かす同じディレクトリにスクリプトシェルを置かないといけない模様。
 (chdirを使ったが、指定のディレクトリに上手く移動してくれないので、 あきらめた。)

shell_execをhtmlspecialcharsで括らないと、中身をうまく認識できないらしく、
スクリプトシェルが動かなかった。
unixのコマンドだとexecだけでも動くようだが、変数などを使っているので、駄目っぽい。


    $command = './converter.sh.sh';
    htmlspecialchars( shell_exec( $command ) ) ;
?>


あとは、form等でボタンをそれなりに作っておく。


動作試験をして、意図するように動いたので、
あとは、stamp等を調整して完了とする。




2012/03/29

PHPの日付計算

PHPの日付の記載方法を調べていたら
参考になるところを発見したので、
貼り付けておく。

http://www.ilovex.co.jp/Division/ITD/archives/2006/03/php.html
株式会社アイロベックス様の
ITプロフェッショナル部のアーカイブより発見。


PHPで1週間前の日付の取得方法がわからなかったので、
調べたところ下記の記述が出てきました。
↓↓↓↓↓↓↓以下PHPコード↓↓↓↓↓↓↓↓↓
//今日の日付を取得(タイムスタンプ)
$date_today = mktime (0, 0, 0, date("m"), date("d"), date("y"));
//一週間前を取得
$date_oneweek = $date_today - 86400 * 7;
↑↑↑↑↑↑↑以上PHPコード↑↑↑↑↑↑↑↑↑
86400というのが一日を表しているらしいです。
その数値×7日で一週間分の数値を求め、それを本日のタイムスタンプから引くと、
一週間前の日付が取得できるといった原理です。
確かにちゃんと動くのですが、本当にこの方法しかないのか??
と思い調べたところ違う書き方もありました。
しかも、上記の記述よりも簡単に書くことができました。

↓↓↓↓↓↓↓以下PHPコード↓↓↓↓↓↓↓↓↓
echo "1日前" . date("Y/m/d",strtotime("-1 day"));
echo "1ヶ月前" . date("Y/m/d",strtotime("-1 month"));
echo "1年前" . date("Y/m/d",strtotime("-1 year"));
echo "1週間前" . date("Y/m/d",strtotime("-1 week"));
↑↑↑↑↑↑↑以上PHPコード↑↑↑↑↑↑↑↑↑
1日前,1週間前,1年前,それに加えて1週間前もこのコードで取得できます。
上記コードだと、本日から○日後の日付が取得できますが、
次のコードだと、指定日付から○日後の日付が取得できます。
↓↓↓↓↓↓↓以下PHPコード↓↓↓↓↓↓↓↓↓
echo "1日前" . date("Y/m/d",strtotime("-1 day" ,strtotime("2005/12/10")));
echo "1ヶ月前" . date("Y/m/d",strtotime("-1 month" ,strtotime("2005/12/10")));
echo "1年前" . date("Y/m/d",strtotime("-1 year",strtotime("2005/12/10")));
echo "1週間前" . date("Y/m/d",strtotime("-1 week" ,strtotime("2005/12/10")));
注意:"2005/12/10"は適当な日付です。ここに指定したい日付を記述して下さい。
↑↑↑↑↑↑↑以上PHPコード↑↑↑↑↑↑↑↑↑

また、PHPで何か発見したら報告します。