2021/01/21

Postgresql データ型変換 char numeric date関連

日付の取り扱いでよく使うもののオボエガキ

【1】今日の日付をnumericに20210121に形で格納したい場合
  now()をcharでYYYYMMDD型に加工した後に、numberで8桁の数値に変えればよい
結果  to_number(to_char(now(), 'YYYYMMDD'),'99999999')

 

【2】8桁の数字20210121をタイムスタンプ型にしたい場合
結果 to_timestamp(to_char(’20210121’,'0000-00-00'),'YYYY-MM-DD'))

 

【3】2021-01-21 12:00:00.0 を 2021-01-21のタイムスタンプ型で扱いたい場合
結果 to_timestamp(to_char(’2021-01-21 12:00:00.0’,'YYYY-MM-DD'),'YYYY-MM-DD')

 

※【2】と【3】は同じタイムスタンプ型になっているので、
where等で 【2】-【3】> INTERVAL '3 days' 等で経過日数を条件としたり出来る。

 

to_charの扱いとして
to_char(1111,'99999') ⇒ ' 1111' 先頭に空白を含み、指定桁数無視
to_char(1111,'FM99999') ⇒ '1111' 空白なし指定桁数無視
to_char(1111,'00000') ⇒ ' 01111' 先頭に空白と含み指定桁数のゼロを付加
to_char(1111,'FM00000') ⇒ '01111'  空白なし指定桁数のゼロ付加

となる FMをつけないと格納できないようなDBもあり得る。

2020/08/19

centos7 sambaサーバにcifsでマウントする

windowsユーザの為に、samba

接続したい名前を検索する。

 # smbclient -L 192.168.0.xxx -U%


        Sharename       Type      Comment
        ---------       ----      -------
        info            Disk      hogehoge Utilities
        share           Disk      hogehoge
        share2          Disk
        share3          Disk
        IPC$            IPC       IPC Service (hogehoge)
Reconnecting with SMB1 for workgroup listing.

        Server               Comment
        ---------            -------

        Workgroup            Master
        ---------            -------
        WORKGROUP            hogeFile


マウントしたい先は、//192.168.0.xxx/share2 と分かった。

# mount //192.168.0.2/share2 /home/hoge/mnt/ -o username=<sambaの登録ユーザ名>,password=<その人のパスワード>

 マウント先でシンボリックリンクを有効にしたい際は、

 # mount //192.168.0.2/share2 /home/hoge/mnt/ -o username=<sambaの登録ユーザ名>,password=<その人のパスワード>,mfsymlinks

と末尾に ,mfsymlinksのオプションを付加すること。

 接続先のcifsのヴァージョン古い場合は、ver2.0等の追記が必要とのことだが、

デフォルト値で接続できたので、このまま運用する。

 接続解除

# umount /home/hoge/mnt

 

 

ディレクトリのパーミッション一括変更処理

新たなユーザと新たなグループを作成し、既存のディレクトリのパーミッションを
数百個一括で変換したい事案が出たので、オボエガキ

findを使ってディレクトリを絞ってパイプでxargsに投げる方法

 

# find /home/hogehoge/test -type d -user nobody -perm 0755 -print | xargs chmod 644


『/home/hogehoge/test』配下にある『nobodyユーザ』の
パーミッション『0755』のディレクトリを『フルパス形式の標準出力』にして
『パイプ』以降の 『xargs』コマンドを使って『フルパス形式の標準出力』に対して、
パーミッション『644』を定義する。

findコマンド
find <処理したいディレクトリの先頭> <オプション>
オプション
-type d ディレクトリファイルを検索
-user nobody ユーザnobodyのファイルのみ検索
-perm 0755 パーミッションが755のものを検索
-print 見つけたファイルをフルパスで出力

| xargs chmod 644
パイプ『|』の右側へ左側のコマンドを投げる
xargs 標準入力やファイルからリストを読み込み、コマンドラインを作成して実行
chmod 644 パーミッションを644に変更

同じような操作方法として、パイプを使わずに パイプ以降を
-exec chmod 644 {} + と記述する方法もあるが、

xargsよりもexecのほうが処理の手順が多く、ファイル数が多くなるほど負荷がかかるため、
基本はxargsを推奨とのこと。
コマンドの分かりやすさからも、xargsのほうがよさそう。

2020/07/28

phpmailer のSMTP送信で嵌った際の対処

表題に行きつくまで2時間ほど嵌ったのでオボエガキ

以前のphp5.4.16では何の問題もなく動いていたのだが
新しいサーバがPHP 7.2.21で稼働している。

PHP5.6から、verify_peerのデフォルトがtrueになったそうで、
SMTP認証をする際に、証明書を求められてエラーが返ってくる。
自己署名証明書も駄目っぽいので、証明書の設定をしないでSMTPを使いたいとき

verify_peerを使いませんと宣言すればよい
と先人は簡単に仰っていたが、ここに行きつくまで2時間かかった・・・。

$mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
);



以下、phpのサンプル

<?php

//----------
//メール作成
//----------

//PHPMailer ライブラリ読み込み
use PHPMailer\PHPMailer\PHPMailer;//PHPMailerの呼び出し
require_once("./vendor/autoload.php" );//位置は適宜設定のこと

mb_language("japanese");//言語設定、内部エンコーディングを指定mb_internal_encoding("UTF-8");

$files = "generate.csv";//アドレスは適宜設定のこと
//日本語添付メールを送るための設定
$to = "hoge@hoge.jp"; //宛先 必須
//$cc = "";
//$Bcc = "";
$subject = "メールのタイトル名";
$body ="本文\n";
$body.="添付のcsvファイルをご確認のこと。\n";
$body.="\n";
$from = "hoge2@hoge.com"; //送り主
$fromname = "送信者名";

//PHPMailerのインスタンス生成
$mail = new PHPMailer(true);//Exceptionを使う場合はtrueにする事使わないときは()でも動く
$mail->CharSet = "iso-2022-jp";
$mail->Encoding = "7bit";

//SMTPサーバ設定
$mail->IsSMTP();
//$mail->SMTPDebug = 0; // 0:デバッグOFF 1:デバッグON
$mail->SMTPAuth = TRUE;
$mail->Host = 'mail.hoge.jp:587';
$mail->Username = 'hoge';
$mail->Password = 'hogehoge';
$mail->SMTPSecure = 'tls'; //TLS
$mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
);
$mail->AddAddress($to);
//$mail->AddCC($cc);
//$mail->AddBcc($Bcc);
$mail->From = $from;
$mail->FromName = mb_encode_mimeheader(mb_convert_encoding($fromname,"JIS","UTF-8"));
$mail->Subject = mb_encode_mimeheader(mb_convert_encoding($subject,"JIS","UTF-8"));
$mail->Body = mb_convert_encoding($body,"JIS","UTF-8");

//添付ファイル
$mail->AddAttachment($files);

//メールを送信
if (!$mail->Send()){
echo("Failed to send mail. Error:".$mail->ErrorInfo);
}else{
echo("Send mail OK.");
}


?>


このような記述で動作した。


後日追記
証明書を取得してpostfixのsmtpd_tls_cert_file などにPKCS12形式のcrtファイル
を配置し、テストしたところ、
verify_peerについての記述をしなくとも、正しく動いた。





twilio Enable Two-Factor Authentication (2段階認証)設定

Twilioから
[Action Required] You must enable Two-factor authentication on your Twilio accounts by October 12, 2020

というメールが来た。
中を見ると、2020年の10月12日からセキュリティ上2段階認証を要求します。
2段階認証を許容していないとロックアウトされてしまうので、設定変更してね
という内容だった。


    1.Login to Twilio Console
    2.Go to “User Settings” page (below your name on the top right corner) in Console
    3.In the "Enable Two-Factor Authentication (2FA)" section, select desired 2FA level
     and click “Update 2FA Settings” to save your selection.
    4.In the "Two-Factor Authentication (2FA) Methods" section, select the desired 2FA method
     and click “Update 2FA Method” to save your selection.
    5.Users enabling 2FA for the first time will be required to go through a one-time login
     and verification process with your new 2FA method of choice.

      手順に従って設定してみた。

      1.今までのようにログインする。
      2.右上のユーザー名をクリックして、User Settings画面に移動
      3.Enable Two-Factor Authentication (2FA) の
        30日毎に認証を選択し(毎回は流石に面倒と判断)
        Update 2FA Settings をクリック
      4.認証画面に飛ばされるので、 日本(+81)を選んで、ユーザ登録した際の
        sms番号(090-xxxx-yyyyなら90xxxxyyyy)を入力して送信
      5.携帯にsmsが飛んでくるので、認証コードを入力する。
      6.トラブル用の回復コードが飛んでくるので、携帯のsimが使えなくなった場合など
        の為に、メモっておいたほうがいいかも。
      7.無事ログインできた。

       メールにある、 In the "Two-Factor Authentication (2FA) Methods については、
      再度ログイン後に選択可能だったので、最初の一回目は テキストメッセージが
      飛んでくるようだ。
      認証コードを送信するための画面の説明は図入りの解説ページを設けても
      良いと思ったけど、twilioを使っている人は、全くの素人ではないだろうから
      自力で何とかするんだろう・・・。

      認証方法については、
      Authy app とあるので、アプリからの認証も出来る模様。
      https://apps.apple.com/jp/app/twilio-authy/id494168017 
      https://play.google.com/store/apps/details?id=com.authy.authy&hl=ja
      面白そうだけど、そもそもそんなにログインしないからテキストでいいや。

      2020/07/07

      inotifywait ディレクトリ監視から自動動作のサンプル

      ディレクトリ監視をして、業務効率化を図るべく、
      今更感満載ながらinotifywaitに手を出してみた。
      
      
      yumでインストールをする
      
      
      epelレポジトリにあるので、未導入時はepel-releaseをインストール
      # yum install epel-release 
       
      inotify-toolsをインストールする。
      # yum install inotify-tools 
      ヴァージョン確認 
      # inotifywait --help
      inotifywait 3.14
       
       
      動作は、ワンライナーでもOKだが、
      シェルスクリプトにて動作させたほうが、汎用性が高い。
       
      シェルスクリプトの例
      先駆者の方々の歴史を参考に
      今回は、pdftkと連携させ、監視ディレクトリにpdfファイルが新規作成されたら
      作業用ディレクトリに移動しPDFに作業済みスタンプを押して、
      作業済ディレクトリに保存という作業を想定。
       
      
      
      doSetStamp.sh
      
      
      ここから
      
      
      #!/bin/sh
      export PATH="/usr/local/bin:$PATH"#pdftkのパスを通す
      MONITORDIR="/home/hoge/work" #監視ディレクトリ指定
      ##スタンプは /home/hoge/stamp/back.pdfを想定
       
      inotifywait -m -r -e create --format '%w%f' "${MONITORDIR}" | while read NEWFILE
      do
        cd /home/hoge/work
        file=$(basename "${NEWFILE}" .pdf)
        mv "$file".pdf /home/hoge/work/"$file".pdf;
        cd /home/hoge/work/
        pdftk /home/hoge/work/"$file".pdf stamp ./stamp/back.pdf output /home/hoge/work/done/"$file"`date "+%Y%m%d"`.pdf;
        rm "$file".pdf
      done
      
      
      ここまで
      
      
      
      
      inotifywaitでなく、シェルのルールの問題だが、
      ダブルクオーテーションで括らないと、半角スペースでコマンドが止まってしまう。
      Windowsユーザが使うので、どうしても半角スペース問題は、加味しておかないと
      想定通りに動かない。
       
      バックエンドで動かす場合は、 
      $nohup doSetStamp.sh &
      のようにする。
      
      
      pdf以外のファイルをディレクトリに配置しない方法として、
      
      
      do~doneの制御にifで判別させて仕分ける方法が最も簡単だと思う。
      if [[ "$file" =~ .*pdf$ ]]; then  
       ここに動作させたい処理を書く; 
      else
       pdfファイル以外の処理を書く;  
      fi
       
       
      
      

      2020/05/14

      SPAM対策

      不覚にも、メールサーバのユーザパスワードが突破され、

      50件程度の踏み台にされてしまったので、対策を行った。

      先ずは、ユーザのパスワードを即座に変更

      # passwd <ユーザ名>
      Changing password for user <ユーザ名>.
      New password:
      Retype new password:
      passwd: all authentication tokens updated successfully.

      メーラー等の設定を修正する。

      スパム送信元のIPアドレスを探る。
        # tail -10000 /var/log/maillog | grep "LOGIN"
      May 14 05:29:03 www postfix/smtpd[xxxx]: xxxxxxxxxxxx: client=unknown[141.XXX.XXX.XXX], sasl_method=LOGIN, sasl_username=ごめんなさい・・・確かに、ヨーロッパのサーバ(ここも踏み台?)に突破されています。

      postfixに拒絶するIPアドレスを指定する。
      # vi /etc/postfix/main.cf

      末尾に
      smtpd_client_restrictions=
      permit_mynetworks,
      check_client_access hash:/etc/postfix/reject_ip,
      permit

      smtpd_client_restrictions で接続の許可、拒否の定義をする。

      permit_mynetworks, $mynetworksに書いたアドレスは許可する。

      check_client_access hash:/etc/postfix/reject_ip, 指定するipを拒否

      permit 上記以外を許可

      拒否するIPアドレス一覧を作成

      記載方法は、拒否したいIPアドレス、ドメイン + REJECTと記載。


      # nano /etc/postfix/reject_ip

      send.hogehoge.com REJECT
      141.XXX.XXX.XXX REJECT
      141.XXX.XXX REJECT

      reject_ipをDB形式に変換
      # postmap /etc/postfix/reject_ip

      Postfixをリロード
      # systemctl restart postfix

      設定が反映される。

      パスワードは、乱数生成が必須とまではいかないまでも、
      ある程度読まれないものにしないとだめだなぁ・・・
      突破されるとは思わなんだ・・・。

      2020/04/05

      slackの登録とbot起動 終了

      今更ながら、slackbotに手を出してみる

      参考にさせて頂いたところ
      https://se.miyabikno-jobs.com/entrance-labotlatori/

      Hubotを使う方法が簡単なようなので、上記を参考に導入

      01.slackのアカウント取得
      02.Hubotのアプリを追加
      03.HubotのAPIトークンを取得
      04.pythonのライブラリ slackbotをインストール
         $ sudo apt-get install python-3-pip
         $ sudo pip3 install slackbot
         $ mkdir slackbot
         $ cd slackbot
      05. $ touch slackbot_settings.py bot.py botmodule.py
         ・slackbot_settings.py:Botの設定を書くためのファイル(名称変更不可)
         ・bot.py:Botを起動するための実行ファイル(名前は任意)
         ・botmodule.py:Botの応答を記述するためのモジュール(名前は任意)
      06.$ nano slackbot_settings.py

      # 「API_TOKEN」にはSlackから取得したAPIトークンを記述
      API_TOKEN = "XXXXXXXXXXXXXXXXXXX"
      # 知らない言葉を聞いた時のデフォルトの応答
      DEFAULT_REPLY = "その言葉の意味は学習していません"
      # 外部ファイルを読み込む。botmodule.pyを読込
      PLUGINS = [
      'slackbot.plugins',
      'botmodule',
      ]

      07.$ nano bot.py

      from slackbot.bot import Bot
      # Botを起動する
      def main():
      bot = Bot()
      bot.run()
      if __name__ == "__main__":
      main()

      08.$ nano botmodule.py

      from slackbot.bot import respond_to
      from slackbot.bot import listen_to
      # 「respond_to」はメンションする(@でターゲットを指定すること)と応答する
      @respond_to('よろしく')
      def greeting_1(message):
      # Slackに応答を返す
      message.reply('よろしくお願いします!')
      # 「listen_to」はメンションがなくても応答する
      @listen_to('コニチハ')
      def greeting_2(message):
      message.reply('コニチハ')

      09.$ nohup python3 bot.py &
        ssh接続を切っても稼働するようにnohup ~ &で起動
            再度sshで接続し、プロセスを停止さえたい場合は、
            $ ps x
            にて pyhon3 bot.py のプロセスidを調べて、
        $ kill -9 
           として停止させる。

      ログインシェルがsshを閉じる際にSIGHUPを投げるため、プロセスが終了してしまうと思っていた。
      nohupはSIGHUPのシグナルハンドラをSIG_IGNに設定、つまり「受信しても無視」する設定にして、コマンドラインで指定されたジョブを実行している。 
      nohupで起動した時点ではRUNNNINGだが、端末が閉じられた後、標準入力に対してread()するようなプログラムでは、(5分ごとに読みなおしなどの動作が入るもの)はcloseしてしまっていて、
      EOFを返してきてしまう。


      nohupを使わなくても停止しないケースもあるようだが、説明が難しい。
      非常に詳しくテストされた解説が掲載されている
      https://www.glamenv-septzen.net/view/854
      実際は、SIGHUPのデフォルト処理はプロセス終了となっており、SIGHUPの受信にかかわらず、プロセスが終了するとき、そのプロセスがセッションリーダーだった場合、カーネルからそのセッションのフォアグラウンドプロセスグループに対してSIGHUPが送信されるらしい。
      また、カーネル側で放置しているバックグラウンドジョブに対しても、シェル(bash)側で終了時にSIGTERM/SIGCONTを送信する事があるためというのが実態のようだ。

      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 が直ぐに思いつかなかった・・・。

      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"

      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に引き上げが必要だろう。
      動作確認とか大変だなぁ

      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;
      ?>

      こんな感じ

      やっぱり、困ったら一人で頑張らないで、公式サイトのメソッドを見るべきだ
      と感じた。

      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等でアップするなりが必要。

      2019/07/01

      シェルスクリプトが動かない場合

      プログラムを書いて試験して
      予定通りに動いたので、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コマンドは端折って記載するより全部書いたほうが早いと云うのが面白い。

      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のインストール
      $ 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開始
      4.bash-4.2# touch /.autorelabel でSELinuxを有効にする
      5.bash-4.2# passwd でrootパスワードを設定する。
      6.bash-4.2# exec /sbin/init  通常モードへ移行する。

      考察
      switch_root:/# exit の再起動がうまくないようだ。
      rd.break enforcing=0 と宣言しなくとも、SELinuxは無効化される様子。
      passwd &lt;管理ユーザ>
      としてパスワードを強制上書きできるが、リラベリングに、えらく時間がかかった。



      以下の手順でも再設定はできたので、間違いではないと思われる。
      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で確認すると、

      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等をインストールすると両立できた。

      2018/11/16

      postfix メールキューのエラー 大量のメールを誤送信してしまい、遅延がひどい場合の措置

      サーバ内のメール転送プログラム実行中にエラーが生じた際に、
      エラー警告メールを送信し、エスケープする処理を盛り込んだのだが、
      エスケープの記述をしくじり、エンドレス送信が生じてしまった。

      2時間程経過した際に以上に気づき、即座にプログラムは停止させ、/var/spool/mail/配下の指定アドレスの中身は処理したのだが、
      postfixのキューに大量の残骸が残ってしまった。
      遅延の遅延の遅延を繰り返し、頑張って送ってきてはいるが、
      1万数千単位のメールが何時までも送られてくるため、当該ユーザの
      通常のメールにも遅延が生じてしまっている状態。

      そこで、postfixのキューを何とかして、通常の状態に戻してみた。

      幸い、該当のメールのサイズが2kBと非常に小さいもので、他の遅延が殆どなかったので、
      さらっと内容を確認して、該当のメールだけを削除する。

      qmgr キューマネージャーにてメッセージはキューを通過する。

      格納されている先

      /var/spool/postfix/incoming リモート受信した最新のメッセージ格納
      /var/spool/postfix/active 処理中メッセージ
      /var/spool/postfix/bounce  配信できなかったメールID毎のログ 
      /var/spool/postfix/corrupt  postfixの形式に則ってないメッセージ格納 
      /var/spool/postfix/deferred 配信不能だがリトライする。
      /var/spool/postfix/hold     無期限保存する際利用
      /var/spool/postfix/defer 一時的に配送不能なメッセージリトライする。


      既に、 /var/spool/mail/配下の指定アドレスの中身は処理済みの場合、
      問題は、
      deferredとdeferに残骸が有ると、何度もリトライを繰り返してしまう点にある。
       
      そこで、 defer配下をfindしてファイルサイズ2kのものをxargsで渡して削除 
      # find /var/spool/postfix/defer/ -size 2k | xargs rm -rf
       
      マジで全部消えるので、ほんとにそのサイズで大丈夫か?を確認すること 
      ※ -execだとファイルの数だけコマンドを投げる仕様のようで、時間がかかってしまう。
        今回1万数千回の実行は xargs の方が向いている。
       
      同様に、deferredでも行う。
      # find /var/spool/postfix/deferred/ -size 2k | xargs rm -rf
       
      その後、 残った問題の無いものを強制送信。
      # postfix flush
       
      最後にキューをきれいにする
      # postsuper -d ALL 
      
      
      キューがきれいになったか確認
      # postqueue -p
      Mail queue is empty

      これで、正常な状態に戻っている(はず)
      小生の環境では、これで正常に配信されるようになった。

      この方の解説が非常にわかりやすかった。ありがとうございます。
      kazupon.com様

      2018/11/06

      SUBARU XV DBA-GT7 CADデータ

      現行のSUBARU(スバル)XVのCADデータが見つからず・・・。
      平面図が欲しかったが、SUBARUさんも3面図のみの掲載・・・。
      平面図を作成するために、結局全部書いてしまった・・・。

      誰トク?なCADデータだが、約2,500台/月の販売実績だし、
      ちょっとリコール出てるけど、車に問題はないし、
      オーナー様にご利用頂ければと思い、公開。


      FC2に「SUBARU_XV_DBA_GT7.zip」でアップロードしてます。(JW_CAD)

      SUBARU(スバル)XV 2017年5月~ DBA-GT7型 2.0i-Sアイサイト