土日、祝祭日をカウントしないで、経過日数から処理を行いたい。
休日テーブルのようなものを作って、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 が直ぐに思いつかなかった・・・。
2019/12/12
2019/11/22
PHP SMS APIサービスのテスト Twilio送信内容の確認
昨日の投稿の続き
送った内容をコンソールでなく、ブラウザ上で確認したい。
検索等の実装も可能なようだ。
先ずは、一覧を表示できないと話にならないので、サンプルを作成してみる。
PHPサンプル list_messages.php
<?php
require("/autoloadが置いてあるでぃてくとりをフルパスで指定/autoload.php" );
use Twilio\Rest\Client;
//定義
$sid = "アカウントのSID";
$token = "アカウントのAUTHTOKEN";
$twilio = new Client($sid, $token);
$messages = $twilio->messages
->read(array(), 20);//取り合えず20個まで
foreach ($messages as $record) {
print($record->to);//toで送信先の番号
print($record->body);//送信メッセージの内容
}
?>
送信結果を取りたいのであれば、
body
date_sent
status
to
body
で十分な気がする。
取得できる配列は以下のようだ。
JSON APIの記載があった。
"account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"api_version": "2010-04-01",
"body": "testing",
"date_created": "Fri, 24 May 2019 17:18:27 +0000",
"date_sent": "Fri, 24 May 2019 17:18:28 +0000",
"date_updated": "Fri, 24 May 2019 17:18:28 +0000",
"direction": "outbound-api",
"error_code": 30007,
"error_message": "Carrier violation",
"from": "+12019235161",
"messaging_service_sid": "MGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"num_media": "0",
"num_segments": "1",
"price": "-0.00750",
"price_unit": "USD",
"sid": "MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"status": "sent",
"subresource_uris": {
"media": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages/SMb7c0a2ce80504485a6f653a7110836f5/Media.json",
"feedback": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages/SMb7c0a2ce80504485a6f653a7110836f5/Feedback.json"
},
"to": "+18182008801",
"uri": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages/SMb7c0a2ce80504485a6f653a7110836f5.json"
送った内容をコンソールでなく、ブラウザ上で確認したい。
検索等の実装も可能なようだ。
先ずは、一覧を表示できないと話にならないので、サンプルを作成してみる。
PHPサンプル list_messages.php
<?php
require("/autoloadが置いてあるでぃてくとりをフルパスで指定/autoload.php" );
use Twilio\Rest\Client;
//定義
$sid = "アカウントのSID";
$token = "アカウントのAUTHTOKEN";
$twilio = new Client($sid, $token);
$messages = $twilio->messages
->read(array(), 20);//取り合えず20個まで
foreach ($messages as $record) {
print($record->to);//toで送信先の番号
print($record->body);//送信メッセージの内容
}
?>
送信結果を取りたいのであれば、
body
date_sent
status
to
body
で十分な気がする。
取得できる配列は以下のようだ。
JSON APIの記載があった。
"account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"api_version": "2010-04-01",
"body": "testing",
"date_created": "Fri, 24 May 2019 17:18:27 +0000",
"date_sent": "Fri, 24 May 2019 17:18:28 +0000",
"date_updated": "Fri, 24 May 2019 17:18:28 +0000",
"direction": "outbound-api",
"error_code": 30007,
"error_message": "Carrier violation",
"from": "+12019235161",
"messaging_service_sid": "MGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"num_media": "0",
"num_segments": "1",
"price": "-0.00750",
"price_unit": "USD",
"sid": "MMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"status": "sent",
"subresource_uris": {
"media": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages/SMb7c0a2ce80504485a6f653a7110836f5/Media.json",
"feedback": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages/SMb7c0a2ce80504485a6f653a7110836f5/Feedback.json"
},
"to": "+18182008801",
"uri": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages/SMb7c0a2ce80504485a6f653a7110836f5.json"
2019/11/21
PHP SMS APIサービスのテスト Twilio 登録から送信テスト完了まで
SMS APIサービスの実装テストにあたりTwilioさんのトライアル版を試してみた。
アカウント取得
ブラウザがchromeでないと上手くいかなかった。
https://jp.twilio.com/try-twilio/kddi-web
2019年に業務提携があったようで、トライアルアカウント取得のページが
複数存在するようだ。ここで、取得できた。
性、名、メールアドレス、パスワード(14文字以上)
を入力してトライアルアカウント作成をすると
ログインする。
その後、2段階式の認証が入り、SMSが有効な電話番号を求めてくるので、
入力して送信すると、認証数列がSMSに届くので、
それを入力して登録完了。
PHPへの実装
composerにてtwilio-phpのライブラリを取得
任意のフォルダにて
$ composer require twilio/sdk
処理されて
Generating autoload files
サンプルプログラム sms_send.php
<?php
require("/autoloadが置いてあるでぃてくとりをフルパスで指定/autoload.php" );
use Twilio\Rest\Client;
$account_sid = 'ダッシュボードのアカウントSIDを記載';
$auth_token = 'ダッシュボードのAUTH TOKENを記載';
$twilio_number = '+120********';//取得したTwilioの電話番号テストは+120のみ許容
$client = new Client($account_sid, $auth_token);
$client->messages->create(
'+8190********',//090の場合日本は+81なので090が+8190となる。トライアル時は登録した電話番号のみ許容される。
[
'from' => $twilio_number,
'body' => 'SMS送信テスト'
]
);
?>
実行してみる
$ php sms_send.php
PHP Fatal error: Uncaught exception 'Twilio\Exceptions\RestException' with message '[HTTP 426] Unable to create record: Upgrade Required' in /var/www/html/vendor/twilio/sdk/Twilio/Version.php:85
Stack trace:
#0 /var/www/html/vendor/twilio/sdk/Twilio/Version.php(219): Twilio\Version->exception(Object(Twilio\Http\Response), 'Unable to creat...')
#1 /var/www/html/vendor/twilio/sdk/Twilio/Rest/Api/V2010/Account/MessageList.php(70): Twilio\Version->create('POST', '/Accounts/AC5c4...', Array, Array)
#2 /var/www/html/maildistributer/test/twilio_test.php(20): Twilio\Rest\Api\V2010\Account\MessageList->create('+8190********', Array)
#3 {main}
thrown in /var/www/html/vendor/twilio/sdk/Twilio/Version.php on line 85
ん?
426エラーが返ってきたので、
twilioの仕様を確認したところ、tls1.2を強要とのこと
phpinfoで知らべたところ稼働中のサーバは
opensslは1.2対応していたが、
cURLのNSSが/3.15でTLS1.2に対応していなかった。(3.283.19.1-6以降以上を要求らしい)
手っとり早い方法を探したところ、NSS/3.28以上のパッケージをインストールしてから
curlをアップデートするのが最速とのことだったので、
# yum install -y https://rpms.southbridge.ru/rhel7/stable/x86_64/southbridge-stable-release-1.0-el7.southbridge.noarch.rpm
# yum update curl
依存処理に結構時間がかかったが、何とか処理完了
# systemctl restart httpd.service
phpを再起動
これも、壊したか?と不安になる位 えらく時間がかかった・・・。
再度テスト
$ php sms_send.php
届いた!
登録から送信完了まで作業時間が約1時間半だった。
2018-9月にTLS1.3がリリースされたので、
近いうちにTLS1.3(openssl 1.1.1)にアップデートが必要になるものと
推測される。
なにやら攻撃を受ける可能性があるなどの情報もありもう少し様子見しようかな
と思っているが、そろそろ、PHPも7.2に引き上げが必要だろう。
動作確認とか大変だなぁ
アカウント取得
ブラウザがchromeでないと上手くいかなかった。
https://jp.twilio.com/try-twilio/kddi-web
2019年に業務提携があったようで、トライアルアカウント取得のページが
複数存在するようだ。ここで、取得できた。
性、名、メールアドレス、パスワード(14文字以上)
を入力してトライアルアカウント作成をすると
ログインする。
その後、2段階式の認証が入り、SMSが有効な電話番号を求めてくるので、
入力して送信すると、認証数列がSMSに届くので、
それを入力して登録完了。
PHPへの実装
composerにてtwilio-phpのライブラリを取得
任意のフォルダにて
$ composer require twilio/sdk
処理されて
Generating autoload files
サンプルプログラム sms_send.php
<?php
require("/autoloadが置いてあるでぃてくとりをフルパスで指定/autoload.php" );
use Twilio\Rest\Client;
$account_sid = 'ダッシュボードのアカウントSIDを記載';
$auth_token = 'ダッシュボードのAUTH TOKENを記載';
$twilio_number = '+120********';//取得したTwilioの電話番号テストは+120のみ許容
$client = new Client($account_sid, $auth_token);
$client->messages->create(
'+8190********',//090の場合日本は+81なので090が+8190となる。トライアル時は登録した電話番号のみ許容される。
[
'from' => $twilio_number,
'body' => 'SMS送信テスト'
]
);
?>
実行してみる
$ php sms_send.php
PHP Fatal error: Uncaught exception 'Twilio\Exceptions\RestException' with message '[HTTP 426] Unable to create record: Upgrade Required' in /var/www/html/vendor/twilio/sdk/Twilio/Version.php:85
Stack trace:
#0 /var/www/html/vendor/twilio/sdk/Twilio/Version.php(219): Twilio\Version->exception(Object(Twilio\Http\Response), 'Unable to creat...')
#1 /var/www/html/vendor/twilio/sdk/Twilio/Rest/Api/V2010/Account/MessageList.php(70): Twilio\Version->create('POST', '/Accounts/AC5c4...', Array, Array)
#2 /var/www/html/maildistributer/test/twilio_test.php(20): Twilio\Rest\Api\V2010\Account\MessageList->create('+8190********', Array)
#3 {main}
thrown in /var/www/html/vendor/twilio/sdk/Twilio/Version.php on line 85
ん?
426エラーが返ってきたので、
twilioの仕様を確認したところ、tls1.2を強要とのこと
phpinfoで知らべたところ稼働中のサーバは
opensslは1.2対応していたが、
cURLのNSSが/3.15でTLS1.2に対応していなかった。(
手っとり早い方法を探したところ、NSS/3.28以上のパッケージをインストールしてから
curlをアップデートするのが最速とのことだったので、
# yum install -y https://rpms.southbridge.ru/rhel7/stable/x86_64/southbridge-stable-release-1.0-el7.southbridge.noarch.rpm
# yum update curl
依存処理に結構時間がかかったが、何とか処理完了
# systemctl restart httpd.service
phpを再起動
これも、壊したか?と不安になる位 えらく時間がかかった・・・。
再度テスト
$ php sms_send.php
届いた!
登録から送信完了まで作業時間が約1時間半だった。
2018-9月にTLS1.3がリリースされたので、
近いうちにTLS1.3(openssl 1.1.1)にアップデートが必要になるものと
推測される。
なにやら攻撃を受ける可能性があるなどの情報もありもう少し様子見しようかな
と思っているが、そろそろ、PHPも7.2に引き上げが必要だろう。
動作確認とか大変だなぁ
2019/11/14
CSPRでの乱数生成 (暗号論的疑似乱数生成関数)
この度、セキュリティポリシーの高い
パスワードの自動生成が必要になり、
疑似乱数生成(PR)によりパスワードの生成をしようとしたころ、
安全な乱数でないと駄目です。とNGをもらった。
安全な乱数なんて量子コンピュータでもないと出来ないよ~~
とか、
エントロピーの無駄使いだ!!
とか言っても解決しないので、簡単な方向を模索してみる。
稼働サーバのPHPが5.4なので、当初randメソッドやmt_randメソッドを
SHA256で包括して、SEEDをハッシュ値で生成するから
疑似じゃないでしょ?で行こう思っていたが、
駄目っぽい雰囲気だったので、もう少し調べてみたところ、
PHP5.4でもライブラリを実装するとPHP7からの
CSPRNGである「random_int」メソッドが使えたので、オボエガキ。
ライブラリは、いつものGitHub様から取得
公式からもリンクされるという素晴らしさ!!
https://github.com/paragonie/random_compat
適宜配置
実際のソース
<?php
//ライブラリ読み込み
require_once "./php_lib/random.php";
// 利用可能な文字列の指定
$chars = 'ABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789';
// 変数初期化
$passwd = '';
// ランダムに文字列を生成(12文字)
for ($i = 0; $i < 12; $i++) {
$passwd .= $chars[random_int(0, 35)];//$charsの文字数を修正時は、必ず揃え、35を修正する。
}
//無限ループ注意!! 数字のみ英大文字のみを許容しない
while ( (preg_match('/^[0-9]+$/', $passwd) || preg_match('/^[A-Z]+$/', $passwd)) ){
$passwd = '';//一旦 $passwd をまっさらにする
for ($i = 0; $i < 12; $i++) {
$passwd .= $chars[random_int(0, 35)];//条件充足までループ
}
}
//文字列表示
echo $passwd;
?>
こんな感じ
やっぱり、困ったら一人で頑張らないで、公式サイトのメソッドを見るべきだ
と感じた。
パスワードの自動生成が必要になり、
疑似乱数生成(PR)によりパスワードの生成をしようとしたころ、
安全な乱数でないと駄目です。とNGをもらった。
安全な乱数なんて量子コンピュータでもないと出来ないよ~~
とか、
エントロピーの無駄使いだ!!
とか言っても解決しないので、簡単な方向を模索してみる。
稼働サーバのPHPが5.4なので、当初randメソッドやmt_randメソッドを
SHA256で包括して、SEEDをハッシュ値で生成するから
疑似じゃないでしょ?で行こう思っていたが、
駄目っぽい雰囲気だったので、もう少し調べてみたところ、
PHP5.4でもライブラリを実装するとPHP7からの
CSPRNGである「random_int」メソッドが使えたので、オボエガキ。
ライブラリは、いつものGitHub様から取得
公式からもリンクされるという素晴らしさ!!
https://github.com/paragonie/random_compat
適宜配置
実際のソース
<?php
//ライブラリ読み込み
require_once "./php_lib/random.php";
// 利用可能な文字列の指定
$chars = 'ABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789';
// 変数初期化
$passwd = '';
// ランダムに文字列を生成(12文字)
for ($i = 0; $i < 12; $i++) {
$passwd .= $chars[random_int(0, 35)];//$charsの文字数を修正時は、必ず揃え、35を修正する。
}
//無限ループ注意!! 数字のみ英大文字のみを許容しない
while ( (preg_match('/^[0-9]+$/', $passwd) || preg_match('/^[A-Z]+$/', $passwd)) ){
$passwd = '';//一旦 $passwd をまっさらにする
for ($i = 0; $i < 12; $i++) {
$passwd .= $chars[random_int(0, 35)];//条件充足までループ
}
}
//文字列表示
echo $passwd;
?>
こんな感じ
やっぱり、困ったら一人で頑張らないで、公式サイトのメソッドを見るべきだ
と感じた。
2019/08/18
apache SELinuxがEnforcingの時、特定のフォルダで読み書きを可能にしたい。
安否確認を自主作成している際、PHPでファイルを読み書きできない状況になったので
調べたところ、コンテキストをいじるには
policycoreutils-python がインストールされていることが条件
yum list policycoreutils-python で調べてなければ、インストールのこと
/var/www/html/test 配下を許容するには
# semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html/test/(/.*)?"
# restorecon -R /var/www/html/test/
でSELinuxの例外を追加する必要がある。
ls -alFZ /var/www/html/test
で確認できる。
嵌ったパターン
既にファイルを生成していて、ディレクトリの属性を
httpd_sys_rw_content_tに変えてrestoreconをしても、
既にあるファイルの属性は変わらない 仕様である。
これが分からず、さんざん悩んだ挙句、
ls -alFZ /var/www/html/対象がいるディレクトリ/
で調べたところ、案の定 rwの属性になっていなかった・・・。
個別に属性付与か、いったん削除して再度scp等でアップするなりが必要。
調べたところ、コンテキストをいじるには
policycoreutils-python がインストールされていることが条件
yum list policycoreutils-python で調べてなければ、インストールのこと
/var/www/html/test 配下を許容するには
# semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html/test/(/.*)?"
# restorecon -R /var/www/html/test/
でSELinuxの例外を追加する必要がある。
ls -alFZ /var/www/html/test
で確認できる。
嵌ったパターン
既にファイルを生成していて、ディレクトリの属性を
httpd_sys_rw_content_tに変えてrestoreconをしても、
既にあるファイルの属性は変わらない 仕様である。
これが分からず、さんざん悩んだ挙句、
ls -alFZ /var/www/html/対象がいるディレクトリ/
で調べたところ、案の定 rwの属性になっていなかった・・・。
個別に属性付与か、いったん削除して再度scp等でアップするなりが必要。
2019/07/01
シェルスクリプトが動かない場合
プログラムを書いて試験して
予定通りに動いたので、cronで自動化をしようと
シェルスクリプトを記載したが、
うまく動かなかった。
logを取ると、プログラムが無いといわれる。
症状を調べると、改行がLFでなくCRLFになっていた。
最近エディタにatomを使っているのだが、
Windowsでatomを使うとデフォルトではCRLFを改行コードに
しているとのことだった。
atomの設定で、
Core Packages ⇒ line-ending-selector に
LF CRLF OS Default があるので、これを
LFにしてあげれば良い。
30分くらい嵌ってしまった。
予定通りに動いたので、cronで自動化をしようと
シェルスクリプトを記載したが、
うまく動かなかった。
logを取ると、プログラムが無いといわれる。
症状を調べると、改行がLFでなくCRLFになっていた。
最近エディタにatomを使っているのだが、
Windowsでatomを使うとデフォルトではCRLFを改行コードに
しているとのことだった。
atomの設定で、
Core Packages ⇒ line-ending-selector に
LF CRLF OS Default があるので、これを
LFにしてあげれば良い。
30分くらい嵌ってしまった。
2019/06/17
PDF解像度変更と一部のページ除去 gsコマンド(GhostScript)
表題の操作をスキャン後のファイルに自動処理で行いたい。
不要なページの削除方法
◆pdftkコマンドを使う
今回はスキャナの為の台紙である一枚目を取り除きたいので、
$ pdftk origin.pdf cat 2-end output modify.pdf
となる。
2枚目だけを取り除きたい場合は、
$ pdftk origin.pdf cat 1 3-end output modify.pdf
オプションの詳細
解像度の変更
◆gsコマンドを使う
オプションが非常に長いが、中途半端に記載すると
処理に時間がかかったので、ファイルサイズ軽減に係るところは全部表記した。
$ gs -q -sOutputFile="/home/user0463/out.pdf" -sDEVICE=pdfwrite -dNOPAUSE -dBATCH -dSAFER -dQUIET -dCompatibilityLevel=1.4 -sColorConversionStrategy=GRAY -dProcessColorModel=/DeviceGray -dGrayImageDownsampleType=/Bicubic -dGrayImageResolution=72 -dMonoImageDownsampleType=/Bicubic -dMonoImageResolution=72 -dColorImageDownsampleType=/Bicubic -dColorImageResolution=72 -dEmbedAllFonts=false -dSubsetFonts=false -dPDFSETTINGS=/printer /home/user0463/moto.pdf
解説
-q 実行時にメッセージを出力しない。
-sOutputFile="出力先ファイル記述"
-sDEVICE=pdfwrite pdf以外の設定 gs -hで確認できる。
-dNOPAUSE ページごとに処理に一時停止をさせない。(これを書かないと遅くなる)
-dBATCH 一連処理させる。
-dSAFER deletefileとrenamefileオペレータを無効
-dQUIET 標準出力への情報を表示しない。
-dCompatibilityLevel=1.4 1.3~1.6まで定義可
-sColorConversionStrategy=GRAY GRAY,CMYK,RGBを指定
-dProcessColorModel=/DeviceGray DeviceGray,DeviceCMYK,DeviceRGBを指定
-dGrayImageDownsampleType=/Bicubic /Subsample, /Average, /Bicubicを指定
-dGrayImageResolution=72 解像度を指定 dpiを指定デフォルト72
-dMonoImageDownsampleType=/Bicubic /Subsample, /Average, /Bicubicを指定
-dMonoImageResolution=72 解像度を指定 dpiを指定デフォルト72
-dColorImageDownsampleType=/Bicubic /Subsample, /Average, /Bicubicを指定
-dColorImageResolution=72 解像度を指定 dpiを指定デフォルト72
-dEmbedAllFonts=false フォントを埋め込むか? true,falseを指定
-dSubsetFonts=false 標準フォントを埋め込むか? true,falseを指定
-dPDFSETTINGS=/printer /screen, /ebook, /printer, /prepress, /defaultを指定
PDFSETTINGS は 低解像度← screen,ebook,printer,prepress →高解像度
defaultは元データを参照するようである。
あとは、シェルスクリプトに記載して、cron や inotifywait
で 自動処理させれば良い。
gsコマンドは端折って記載するより全部書いたほうが早いと云うのが面白い。
不要なページの削除方法
◆pdftkコマンドを使う
今回はスキャナの為の台紙である一枚目を取り除きたいので、
$ pdftk origin.pdf cat 2-end output modify.pdf
となる。
2枚目だけを取り除きたい場合は、
$ pdftk origin.pdf cat 1 3-end output modify.pdf
オプションの詳細
解像度の変更
◆gsコマンドを使う
オプションが非常に長いが、中途半端に記載すると
処理に時間がかかったので、ファイルサイズ軽減に係るところは全部表記した。
$ gs -q -sOutputFile="/home/user0463/out.pdf" -sDEVICE=pdfwrite -dNOPAUSE -dBATCH -dSAFER -dQUIET -dCompatibilityLevel=1.4 -sColorConversionStrategy=GRAY -dProcessColorModel=/DeviceGray -dGrayImageDownsampleType=/Bicubic -dGrayImageResolution=72 -dMonoImageDownsampleType=/Bicubic -dMonoImageResolution=72 -dColorImageDownsampleType=/Bicubic -dColorImageResolution=72 -dEmbedAllFonts=false -dSubsetFonts=false -dPDFSETTINGS=/printer /home/user0463/moto.pdf
解説
-q 実行時にメッセージを出力しない。
-sOutputFile="出力先ファイル記述"
-sDEVICE=pdfwrite pdf以外の設定 gs -hで確認できる。
-dNOPAUSE ページごとに処理に一時停止をさせない。(これを書かないと遅くなる)
-dBATCH 一連処理させる。
-dSAFER deletefileとrenamefileオペレータを無効
-dQUIET 標準出力への情報を表示しない。
-dCompatibilityLevel=1.4 1.3~1.6まで定義可
-sColorConversionStrategy=GRAY GRAY,CMYK,RGBを指定
-dProcessColorModel=/DeviceGray DeviceGray,DeviceCMYK,DeviceRGBを指定
-dGrayImageDownsampleType=/Bicubic /Subsample, /Average, /Bicubicを指定
-dGrayImageResolution=72 解像度を指定 dpiを指定デフォルト72
-dMonoImageDownsampleType=/Bicubic /Subsample, /Average, /Bicubicを指定
-dMonoImageResolution=72 解像度を指定 dpiを指定デフォルト72
-dColorImageDownsampleType=/Bicubic /Subsample, /Average, /Bicubicを指定
-dColorImageResolution=72 解像度を指定 dpiを指定デフォルト72
-dEmbedAllFonts=false フォントを埋め込むか? true,falseを指定
-dSubsetFonts=false 標準フォントを埋め込むか? true,falseを指定
-dPDFSETTINGS=/printer /screen, /ebook, /printer, /prepress, /defaultを指定
PDFSETTINGS は 低解像度← screen,ebook,printer,prepress →高解像度
defaultは元データを参照するようである。
あとは、シェルスクリプトに記載して、cron や inotifywait
で 自動処理させれば良い。
gsコマンドは端折って記載するより全部書いたほうが早いと云うのが面白い。
2019/05/17
raspberrypi3のカメラを使ってメール応答型のスクリプト node.jsを活用
やりたいこと
メールを受信すると、raspberrypi3のカメラで撮影し、
メールに添付して指定のメールアドレスに送信するスクリプト。
子供や愛犬の見守りなど目的は同じになるが、
玄関の施錠をしたか?を最寄りの駅で気になった場合に
万が一の為に戻りたくないので作成。
玄関が開き戸だったら、もっといろいろな仕掛けができたのだが・・・。
補足
メール部分は自分でサーバ建てるのが大変なので、
Gmailを利用し、node.jsを使ってメールの送信を常に監視し、
監視中にメールが来るとそれをトリガーにして
カメラで撮影、メールを送信する。
node.jsは『非同期スクリプト』であるため、
fs等を使う場合は、同期させた処理を行う必要がある。
ここで、嵌ってしまった・・・。
カメラの処理に時間がかかり、ファイルが生成される前に
メール送信のためのファイル加工が動作してしまい、
エラーが返って来てしまうので、
別々に動作確認が終わったら、promise 等で同期処理をさせる。
前提
・raspberry-pi3のカメラモジュールを認識済み
・Gmailのアカウント取得、安全性の低いアプリの許可」を有効にしてある。
・nodeが動かせること
◆◆◆成果物◆◆◆
'use strict';
var inbox = require('inbox');
//var nodemailer = require('nodemailer');
//var iconv = require('iconv');
//var conv = new iconv.Iconv("UTF-8", "UTF-8");
const simpleParser = require('mailparser').simpleParser;
var client = inbox.createConnection(false, 'imap.gmail.com', {
secureConnection: true
,auth: {
user:'Gmailアカウント@gmail.com'
,pass:'Gmailパスワード'
}
});
client.on('connect', function() {
console.log('connected');
client.openMailbox('INBOX', function(error) {
if (error) throw error;
});
});
client.connect();
client.on("new", function(message) {
console.log('日時:' + message.date);
console.log('送信者:' + message.from.name + '-' + message.from.address);
console.log('タイトル:' + message.title);
var stream = client.createMessageStream(message.UID);
simpleParser(stream)
.then(mail=> {
console.log('本文(HTMLテキスト):' + mail.textAsHtml);
})
.catch(err=> {
console.log(err);
});
//node.jsはデフォルトで非同期処理を行うため、
//asyncを用いてカメラがsnap.jpgを生成するのを待ち
//Gmailの送信(snap.jpgの添付)、snap.jpgの削除を行っている
//pi-cameraでは上書き保存ができないため、メール送信後に削除しておく。
const async = require('async'); //同期処理のためasync呼び出す
async.series([
function(callback) {
console.log('カメラの処理開始');
//pi-camera の動作ここから
const PiCamera = require('pi-camera');
const myCamera = new PiCamera({
mode: 'photo',
output: `${ __dirname }/snap.jpg`,
width: 640,
height: 480,
nopreview: true,
});
myCamera.snap()
.then((result) => {
// Your picture was captured
})
.catch((error) => {
// Handle your error
});
//pi-camera の動作ここまで
//安全をみて7秒ディレイ
setTimeout(callback, 7000);
}, function(callback) {
console.log('メールの返信開始');
//Gmailで送信ここから
var nodemailer = require('nodemailer')
var fs = require('fs');
// メッセージ内容
var message = {
from : '送信元@gmail.com',
to : '送信先@gmail.com',
subject : 'Reply to request',
text : 'Reply to request,Picture of the Pi-Camera !',
attachments : [{
filename: 'snap.jpg',
content: fs.readFileSync('snap.jpg') //カメラのデータ生成待ち
}]
};
var smtpConfig = {
host: 'smtp.gmail.com',
port: 465,
secure: true, // SSL
auth: {
user : 'Gmailアカウント@gmail.com',
pass : 'Gmailパスワード'
}
};
var transporter = nodemailer.createTransport(smtpConfig);
transporter.sendMail(message, function(err, response) {
console.log(err || response);
});
//ファイル削除
try {
fs.unlinkSync('snap.jpg');
console.log('snap.jpgを削除しました。');
} catch (error) {
throw error;
}
//Gmailで送信ここまで
setTimeout(callback, 1000);
}, function(callback) {
return console.log('処理終了');
}
], function(err, results) {
if (err) {
return console.log('err[' + err + ']');
}
});
}); // client.connect() を閉じる。
コマンド自体はプロンプト状態なので停止はcrtl+Zにて行う。
sshで操作する場合は、forever等で動かさないと、ターミナル閉じた瞬間に
Killされるので注意が必要。
◆◆動作部分解説◆◆
◆メール受信トリガー部分◆
node.jsのパッケージインストール
$ npm install inbox
$ npm install mailparser
まんま、@hideito2000様の掲載内容を使わせていただいた。
//ソース
client.on("new", function(message) {
console.log('日時:' + message.date);
console.log('送信者:' + message.from.name + '-' + message.from.address);
console.log('タイトル:' + message.title);
var stream = client.createMessageStream(message.UID);
simpleParser(stream)
.then(mail=> {
console.log('本文(HTMLテキスト):' + mail.textAsHtml);
})
.catch(err=> {
console.log(err);
});
//この部分にカメラ処理とメール送信を組み込む
});
//ソースここまで
◆pi-cameraのインストール◆
メールを受信すると、raspberrypi3のカメラで撮影し、
メールに添付して指定のメールアドレスに送信するスクリプト。
子供や愛犬の見守りなど目的は同じになるが、
玄関の施錠をしたか?を最寄りの駅で気になった場合に
万が一の為に戻りたくないので作成。
玄関が開き戸だったら、もっといろいろな仕掛けができたのだが・・・。
補足
メール部分は自分でサーバ建てるのが大変なので、
Gmailを利用し、node.jsを使ってメールの送信を常に監視し、
監視中にメールが来るとそれをトリガーにして
カメラで撮影、メールを送信する。
node.jsは『非同期スクリプト』であるため、
fs等を使う場合は、同期させた処理を行う必要がある。
ここで、嵌ってしまった・・・。
カメラの処理に時間がかかり、ファイルが生成される前に
メール送信のためのファイル加工が動作してしまい、
エラーが返って来てしまうので、
別々に動作確認が終わったら、promise 等で同期処理をさせる。
前提
・raspberry-pi3のカメラモジュールを認識済み
・Gmailのアカウント取得、安全性の低いアプリの許可」を有効にしてある。
・nodeが動かせること
◆◆◆成果物◆◆◆
'use strict';
var inbox = require('inbox');
//var nodemailer = require('nodemailer');
//var iconv = require('iconv');
//var conv = new iconv.Iconv("UTF-8", "UTF-8");
const simpleParser = require('mailparser').simpleParser;
var client = inbox.createConnection(false, 'imap.gmail.com', {
secureConnection: true
,auth: {
user:'Gmailアカウント@gmail.com'
,pass:'Gmailパスワード'
}
});
client.on('connect', function() {
console.log('connected');
client.openMailbox('INBOX', function(error) {
if (error) throw error;
});
});
client.connect();
client.on("new", function(message) {
console.log('日時:' + message.date);
console.log('送信者:' + message.from.name + '-' + message.from.address);
console.log('タイトル:' + message.title);
var stream = client.createMessageStream(message.UID);
simpleParser(stream)
.then(mail=> {
console.log('本文(HTMLテキスト):' + mail.textAsHtml);
})
.catch(err=> {
console.log(err);
});
//node.jsはデフォルトで非同期処理を行うため、
//asyncを用いてカメラがsnap.jpgを生成するのを待ち
//Gmailの送信(snap.jpgの添付)、snap.jpgの削除を行っている
//pi-cameraでは上書き保存ができないため、メール送信後に削除しておく。
const async = require('async'); //同期処理のためasync呼び出す
async.series([
function(callback) {
console.log('カメラの処理開始');
//pi-camera の動作ここから
const PiCamera = require('pi-camera');
const myCamera = new PiCamera({
mode: 'photo',
output: `${ __dirname }/snap.jpg`,
width: 640,
height: 480,
nopreview: true,
});
myCamera.snap()
.then((result) => {
// Your picture was captured
})
.catch((error) => {
// Handle your error
});
//pi-camera の動作ここまで
//安全をみて7秒ディレイ
setTimeout(callback, 7000);
}, function(callback) {
console.log('メールの返信開始');
//Gmailで送信ここから
var nodemailer = require('nodemailer')
var fs = require('fs');
// メッセージ内容
var message = {
from : '送信元@gmail.com',
to : '送信先@gmail.com',
subject : 'Reply to request',
text : 'Reply to request,Picture of the Pi-Camera !',
attachments : [{
filename: 'snap.jpg',
content: fs.readFileSync('snap.jpg') //カメラのデータ生成待ち
}]
};
var smtpConfig = {
host: 'smtp.gmail.com',
port: 465,
secure: true, // SSL
auth: {
user : 'Gmailアカウント@gmail.com',
pass : 'Gmailパスワード'
}
};
var transporter = nodemailer.createTransport(smtpConfig);
transporter.sendMail(message, function(err, response) {
console.log(err || response);
});
//ファイル削除
try {
fs.unlinkSync('snap.jpg');
console.log('snap.jpgを削除しました。');
} catch (error) {
throw error;
}
//Gmailで送信ここまで
setTimeout(callback, 1000);
}, function(callback) {
return console.log('処理終了');
}
], function(err, results) {
if (err) {
return console.log('err[' + err + ']');
}
});
}); // client.connect() を閉じる。
コマンド自体はプロンプト状態なので停止はcrtl+Zにて行う。
sshで操作する場合は、forever等で動かさないと、ターミナル閉じた瞬間に
Killされるので注意が必要。
◆◆動作部分解説◆◆
◆メール受信トリガー部分◆
node.jsのパッケージインストール
$ npm install inbox
$ npm install mailparser
まんま、@hideito2000様の掲載内容を使わせていただいた。
//ソース
client.on("new", function(message) {
console.log('日時:' + message.date);
console.log('送信者:' + message.from.name + '-' + message.from.address);
console.log('タイトル:' + message.title);
var stream = client.createMessageStream(message.UID);
simpleParser(stream)
.then(mail=> {
console.log('本文(HTMLテキスト):' + mail.textAsHtml);
})
.catch(err=> {
console.log(err);
});
//この部分にカメラ処理とメール送信を組み込む
});
//ソースここまで
◆pi-cameraのインストール◆
$ npm install pi-camera
作成者のページのサンプルをそのまま使う
//ソース
const PiCamera = require('pi-camera');
const myCamera = new PiCamera({
mode: 'photo',
output: `${ __dirname }/snap.jpg`,
width: 640,
height: 480,
nopreview: true,
});
myCamera.snap()
.then((result) => {
// Your picture was captured
})
.catch((error) => {
// Handle your error
});
//ソースここまで
◆nodemailer でメールを送信させるので、インストール◆ $ npm i -D nodemailer
ソースは皆さまの内容を参照させていただいた。
ありがとうございます。
//ソース
var mailer = require('nodemailer');
mailer.SMTP = {
host: 'smtp.gmail.com',
port: 465,
secure: true, // SSL
auth: {
user : 'Gmailのid@gmail.com,
pass : 'Gmailのパスワード'
}
};
fs.readFile("./snap.jpg", function (err, data) {
mailer.send_mail({
sender: '送信元@gmail.com',
to: '送信先@gmail.com',
subject: 'snapshot-Ent!',
body: 'Snapshot of the Entrance !',
attachments: [{'filename': 'snap.jpg', 'content': picture}]
}), function(err, success) {
if (err) {
// Handle error
}
}
});
//ソースここまで
◆ファイルの削除◆
try {
fs.unlinkSync('snap.jpg');
console.log('snap.jpgを削除しました。');
} catch (error) {
throw error;
}
fsは非同期だが、同じコマンドであれば記載の順に動くようだ。
駄目な場合は、 async の回数を増やせば良い。
◆同期処理◆
async.series([
function(callback) {
console.log('処理開始');
このcallback間にメソッドを記載
setTimeout(callback, 1000);
}, function(callback) { console.log('処理2開始');
setTimeout(callback, 1000);
});
}, function(callback) {
return console.log('処理終了');
}
],
期待した動きができたので、満足。
2019/05/08
CentOS(RedHat系) rootパスワードが分からない際の対策
CentOS7以降、レスキューモード(旧シングルユーザモード)、エマージェンシーモード
ともにrootパスワードを要求される。
しかし、管理者が不慮のアクシデントで対応できない状況となった際に、
どうしてもrootパスワードが必要なことが生じることがある。
今回、どうにもならない状況になってしまったため、操作した。
Procedure 25.6. Resetting the Root Password Using rd.break
いくつか手順を発見したので、残しておく
1.GRUB(ブートするOSを選択する画面)で「e」を押す。
2.rhgb quiet LANG*** を消して、systemd.debug の後ろにrw init=/bin/bashを加える。
3.Ctrl+x でboot開始
としてパスワードを強制上書きできるが、リラベリングに、えらく時間がかかった。
以下の手順でも再設定はできたので、間違いではないと思われる。
mozcの設定がうまくいっていなかったのかもしれないが、自分で構築していないので
どうにもならなかった・・・。
1.GRUB(ブートするOSを選択する画面)で「e」を押す。
2.rhgb quiet を消して、 rd.break enforcing=0 を書き加える。
(linux16の行と書いてあるが、同じ位置で問題なかった。)
※ enforcing=0はSELinuxの制御をオミットする意味とのこと。
3.Ctrl+x でboot開始
4.switch_root:/# mount -o remount,rw /sysroot を入力しエンター
※ファイルシステムを書き換え可能にする。
5.switch_root:/# chroot /sysroot を入力しエンター
※ファイルシステムをroot管理にする
6.sh-4.2# passwd でrootパスワードを設定する。
7.sh-4.2# exit を入力しエンター
8.switch_root:/# exit を入力しエンター
9.再起動し通常のユーザでログイン後ターミナルで新しいパスワードでroot化する。
10.# restorecon -v /etc/shadow を入力しエンター
※rd.breakで操作したrootパスワード格納のshadow定義をデフォルトにする。
※上記をしないと、再起動時にパスワードを誰も読めずログインできなくなる。
11.# setenforce 1 を入力しエンター
※SELinuxを有効にしておく。
以降は、再起動しても問題ない。
一般ユーザのパスワードはそのままで、rootは新しいパスワードが有効になる。
LUKS(Linux Unified Key Setup)を利用している場合は、
上記の操作を開始する時点でパスワードやファイルによる解除が必要となるそうだが、
LUKS は、膨大な (RHEL 7 では 512 文字) 平文テキストのパスフレーズと、非常に大きな (RHEL 7 では 8 MiB) のキーファイルを許可しているそうなので、
導入には、配慮が必要と改めて感じた。
ともにrootパスワードを要求される。
しかし、管理者が不慮のアクシデントで対応できない状況となった際に、
どうしてもrootパスワードが必要なことが生じることがある。
今回、どうにもならない状況になってしまったため、操作した。
Procedure 25.6. Resetting the Root Password Using rd.break
いくつか手順を発見したので、残しておく
1.GRUB(ブートするOSを選択する画面)で「e」を押す。
2.rhgb quiet LANG*** を消して、systemd.debug の後ろにrw init=/bin/bashを加える。
3.Ctrl+x でboot開始
4.bash-4.2# touch /.autorelabel でSELinuxを有効にする
5.bash-4.2# passwd でrootパスワードを設定する。
6.bash-4.2# exec /sbin/init 通常モードへ移行する。
6.bash-4.2# exec /sbin/init 通常モードへ移行する。
考察
switch_root:/# exit の再起動がうまくないようだ。
switch_root:/# exit の再起動がうまくないようだ。
rd.break enforcing=0 と宣言しなくとも、SELinuxは無効化される様子。
passwd <管理ユーザ>としてパスワードを強制上書きできるが、リラベリングに、えらく時間がかかった。
以下の手順でも再設定はできたので、間違いではないと思われる。
mozcの設定がうまくいっていなかったのかもしれないが、自分で構築していないので
どうにもならなかった・・・。
1.GRUB(ブートするOSを選択する画面)で「e」を押す。
2.rhgb quiet を消して、 rd.break enforcing=0 を書き加える。
(linux16の行と書いてあるが、同じ位置で問題なかった。)
※ enforcing=0はSELinuxの制御をオミットする意味とのこと。
3.Ctrl+x でboot開始
4.switch_root:/# mount -o remount,rw /sysroot を入力しエンター
※ファイルシステムを書き換え可能にする。
5.switch_root:/# chroot /sysroot を入力しエンター
※ファイルシステムをroot管理にする
6.sh-4.2# passwd でrootパスワードを設定する。
7.sh-4.2# exit を入力しエンター
8.switch_root:/# exit を入力しエンター
9.再起動し通常のユーザでログイン後ターミナルで新しいパスワードでroot化する。
10.# restorecon -v /etc/shadow を入力しエンター
※rd.breakで操作したrootパスワード格納のshadow定義をデフォルトにする。
※上記をしないと、再起動時にパスワードを誰も読めずログインできなくなる。
11.# setenforce 1 を入力しエンター
※SELinuxを有効にしておく。
以降は、再起動しても問題ない。
一般ユーザのパスワードはそのままで、rootは新しいパスワードが有効になる。
LUKS(Linux Unified Key Setup)を利用している場合は、
上記の操作を開始する時点でパスワードやファイルによる解除が必要となるそうだが、
LUKS は、膨大な (RHEL 7 では 512 文字) 平文テキストのパスフレーズと、非常に大きな (RHEL 7 では 8 MiB) のキーファイルを許可しているそうなので、
導入には、配慮が必要と改めて感じた。
2019/01/17
NTT αNXⅡ v4.00 webシステム設定 のjava
NTT αNXⅡ v4.00 webシステム設定
会社がNTTのネットコミュニティシステムαNXⅡを利用しているのだが、
ブラウザ上で電話帳や電話機の名称等の設定ができる。
javaのバージョンによっては動作しないので、
少し調べてみたので、オボエガキ
少し古い、αNX typeLのマニュアルの200ページくらいに
「次世代のJava Plug-inを有効にする 」設定を無効にする必要があると書いてある。
ところが、Oracleで確認すると、
末尾に
とあり、 Java Pluginが利用できなくなっている。
あわせて、次世代のJava Plug-inを有効無効の制御ができなくなったようだ。
一度、古めの6をインストールして、Webシステム設定を動作できる状況にしてから、
JDK8等をインストールすると両立できた。
会社がNTTのネットコミュニティシステムαNXⅡを利用しているのだが、
ブラウザ上で電話帳や電話機の名称等の設定ができる。
javaのバージョンによっては動作しないので、
少し調べてみたので、オボエガキ
少し古い、αNX typeLのマニュアルの200ページくらいに
「次世代のJava Plug-inを有効にする 」設定を無効にする必要があると書いてある。
ところが、Oracleで確認すると、
Changes in Java SE 6u171 b31
Please note that fixes from prior BPR (6u161 b32) are included in this version.末尾に
Known Issues
deploy
Windows - There is a non-functional Java icon in control panel after installing 6u171 or 7u161
Deployment features in 6u171 and 7u161 have been removed. Installing a
version of the JRE that has deployment technologies support AFTER
having installed the current JRE will cause the Windows Control Panel to
display a non-functional Java Control panel icon.
JDK-8185373 (not public)
とあり、 Java Pluginが利用できなくなっている。
あわせて、次世代のJava Plug-inを有効無効の制御ができなくなったようだ。
一度、古めの6をインストールして、Webシステム設定を動作できる状況にしてから、
JDK8等をインストールすると両立できた。
登録:
投稿 (Atom)