end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

facebook conversion api client for php

facebook conversion api client for perl - end0tknr's kipple - web写経開発

先程のentryのphp版です

目次

form_fb_capi.php

<?php
require_once './form/lib/XeimForm4FacebookConversion.php';

$fb_api = new XeimForm4FacebookConversion();
$form_url = $_POST["referrer"];
$fb_api->notify_to_facebook("sexyxeim_com",$form_url,$_POST);

XeimForm4FacebookConversion.php

<?php
require_once 'XeimForm.php';

class XeimForm4FacebookConversion extends XeimForm {

    function __construct() {
        $this->ini_set();
    }

    function error_mail_subject(){
        return "【FacebookConversion】ERROR通知メール";
    }
    
    function error_mail_body($name_1,$refferer,$endpoint,$http_res_code){
        
        $mail_body =<<<EOF
$name_1 様の申し込みがfacebookへ連携されませんでした。
フォームURL        : $refferer
facebook URL       : $endpoint
HTTP RESPONSE CODE : $http_res_code

EOF;
        return $mail_body;
    }

    function notify_to_facebook($facebook_rule_name, $refferer, $req_params ){
        $func_name = __CLASS__." ".__FUNCTION__;
        $this->write_log("START $func_name for $facebook_rule_name $refferer");

        $facebook_rule = $this->facebook_rule($facebook_rule_name);
        if(! $facebook_rule ){
            $tmp_msg = "ERROR fail $func_name $facebook_rule_name";
            $this->write_log($tmp_msg);
            
            $tmp_msg = print_r($req_params,true);
            $this->write_log($tmp_msg);
            return false;
        }
        
 
        $form_data = [
         ["user_data"       =>
          $this->conv_req_params_for_facebook($req_params, $facebook_rule),
          "action_source"   =>"website",
          "event_name"      =>"FromRequest",
          "event_time"      => time(),
          "event_source_url"=>$refferer]
        ];
        //$this->write_log(print_r($form_data,true));

        $endpoint = $facebook_rule["FACEBOOK_URL"];
        $req_data = [
            "access_token"=>$facebook_rule["ACCESS_TOKEN"],
            "data"=> $this->json_encode($form_data),
        ];

        
        $http_res_code = $this->post_to_facebook($req_data, $endpoint);

        if ( in_array($http_res_code,["200","204"], true) ){
            $tmp_msg = "DONE $func_name $facebook_rule_name";
            $this->write_log($tmp_msg);
            return true;
        }

        $tmp_msg = "ERROR $func_name $facebook_rule_name HTTP_CODE:$http_res_code";
        $this->write_log($tmp_msg);
        $this->notify_error($req_params,$refferer,$endpoint,$http_res_code);

        return false;
    }

    private function notify_error($req_params,$refferer,$endpoint,$http_res_code){
        $func_name = __CLASS__." ".__FUNCTION__;
        
        $mail_body = $this->error_mail_body($req_params['name1'],
            $refferer,
            $endpoint,
            $http_res_code);
            
            //全体のシステム管理者へ、メール通知
            $sendmail = new XeimForm4Sendmail();
            $sendmail->mail_to_sys_admin(self::ERR_MAIL_SUBJECT, $mail_body);
            
            $tmp_msg = "ERROR $func_name";
            $this->write_log($tmp_msg);
            $this->write_log($mail_body);
            $this->write_log(print_r($req_params,true));
        }
        
        private function conv_req_params_for_facebook($org_params, $facebook_rule){
            
            $cooperation_items_def = $facebook_rule["COOPERATION_ITEM"];
            $new_params = [];
            foreach($cooperation_items_def as $facebook_key => $from_key){
            //$this->write_log( "$facebook_key , $from_key" );
             
             if(! isset($org_params[$from_key]) or
                 mb_strlen($org_params[$from_key]) == 0){
                 continue;
             }
             //$this->write_log("$facebook_key $from_key , ".$org_params[$from_key]);
             $new_params[$facebook_key] = $org_params[$from_key];
             # refer to https://developers.facebook.com/docs/marketing-api/conversions-api/parameters
             if( strcmp($facebook_key, "em") == 0 ){
                 $new_params[$facebook_key] = [ hash('sha256', $new_params[$facebook_key]) ];
             }
         }
         
         return $new_params;
    }
            

    private function facebook_rule($rule_name){
        $func_name = __CLASS__." ".__FUNCTION__;

        $conf_dir = $this->conf_dir();
        $file_path = $conf_dir ."/facebook/$rule_name.json";
        
        try{
            $file_obj = new SplFileObject($file_path,"rb");
            $json_str = $file_obj->fread($file_obj->getSize());
        } catch (Exception $e) {
            $tmp_msg = "ERROR fail open $file_path $func_name ". $e->getMessage();
            $this->write_log($tmp_msg);
            return;
        }
        
        $ret_def = $this->json_decode($json_str);
        return $ret_def;
    }

    private function post_to_facebook($postdata, $endpoint){
        $func_name = __CLASS__." ".__FUNCTION__;
        $this->write_log("START $func_name to $endpoint");
        //$this->write_log(print_r($postdata,true));
        
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postdata));
        curl_setopt($ch, CURLOPT_URL, $endpoint);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER,TRUE);
        curl_setopt($ch, CURLOPT_FAILONERROR,   TRUE);

        $res_body_json = curl_exec($ch);
        
        $curl_getinfo = curl_getinfo($ch);
        $status_code = $curl_getinfo["http_code"];
        
        if (curl_errno($ch)) {
            $tmp_msg = "ERROR $func_name $endpoint $status_code $res_body_json";
            $this->write_log($tmp_msg);
            return;
        }
        
        $res_body = $this->json_decode($res_body_json);
        if( $res_body["events_received"] != 1 ){
            $tmp_msg = "ERROR $func_name $endpoint $status_code $res_body_json";
            $this->write_log($tmp_msg);
            return;
        }

        curl_close($ch);
        return (string)$status_code;
    }
}

sexyxeim_com.json

{"//":"ex. https://graph.facebook.com/{API_VERSION}/{PIXEL_ID}/events",
 "FACEBOOK_URL":"https://graph.facebook.com/v12.0/ないしょ/events",
 "ACCESS_TOKEN":"ないしょ",
 "NOTIFY_TO":"hogehoge1@example.com,hogehoge2@example.com",
 "//":"連携項目",
 "COOPERATION_ITEM" : {"em" :"email1"}
}

実行例

$ curl -X POST \
   -F 'email1=hogehoge@gmail.com'  \
   -F 'referrer=https://hoge.example.com/cgi-bin/form.cgi' \
   http://localhost/cgi-bin2/form_fb_capi.php

facebook conversion api client for perl

参考url

facebook conversion api client for perl

#!/usr/bin/perl

use strict;
use warnings;
use utf8;
use Data::Dumper;
use Digest::SHA qw(sha256_hex);
use JSON;
use HTTP::Request::Common;
use LWP::UserAgent;  # need for "cpan install LWP::Protocol::https"

#↓今回の件とは関係ありませんが...
my $LWP_OPT = {file =>"cookies.txt", autosave=>1, ignore_discard => 1};

# ex. https://graph.facebook.com/{API_VERSION}/{PIXEL_ID}/events
my $CAPI_URL = 'https://graph.facebook.com/v12.0/ないしょID/events';
my $CAPI_TOKEN = "ないしょTOKEN";


main();

sub main {
    my $ua = LWP::UserAgent->new;
    $ua->cookie_jar($LWP_OPT);

    #refer to
    # https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/server-event
    my $form_data = [
        {action_source=>"website",
         event_name=>"CatalogRequest",
         event_time=> time(),
         event_source_url=>"https://example.com/test_url",
         custom_data=>{},
         user_data=>{
             em=>[
                 Digest::SHA::sha256_hex('nobody@example.com')
                 ]
         }
        }];

    my $form_data_json = encode_json($form_data);
    # print STDERR "$form_data_json\n";

    my $req_url = "$CAPI_URL?access_token=$CAPI_TOKEN";
    my $req_param = [ access_token=>$CAPI_TOKEN,
                      data=>$form_data_json ];
    
    my $req = POST($req_url, $req_param );
    
    my $res = $ua->request($req);
    
    if( not $res->is_success or
        not chk_response($res) ) {
        error_occured($req,$res);
        return;
    }

    return 1;
}

sub chk_response {
    my ($res) = @_;
    my $res_content_json = $res->content;

    my $res_content = decode_json( $res_content_json );
    if( $res_content->{events_received} eq "1"){
    return 1; # 1 means success.
    }

    print STDERR Dumper($res);
    return; # undef means fail.
}

sub error_occured {
    my ($req,$res) = @_;
    # TODO エラー検知後の通知等
}

__END__

Re: みずほ銀行、みずほFGに対する行政処分について by 金融庁

2021/11/26に発表された

www.fsa.go.jp

によれば、【真因】は

  1. システムに係るリスクと専門性の軽視
  2. IT現場の実態軽視
  3. 顧客影響に対する感度の欠如、営業現場の実態軽視
  4. 言うべきことを言わない、言われたことだけしかしない姿勢

らしい。

デジタル技術普及の加速が職のミスマッチ拡大を前倒し from 三菱総合研究所

以下、三菱総研の 2021/4/28資料です。

f:id:end0tknr:20220116173649p:plain

nginx + http_auth_request_module

先日、上記のentryを記載しましたが、 以下のentryのように http_auth_request_module があれば、 lua-nginx-module よりも楽かも

install wordpress 5.8 to php + iis for win11

wordpress + php + iis の構成は殆ど見たことのない構成ですが、メモ。

目次

step 1 - php + iis for win11 環境

と言っても、先日の以下のurlに記載の通りです。

iis for win11 に fastcgi な php 環境の構築 - end0tknr's kipple - web写経開発

step 2 - mysql for wordrecreate

まず、create database & create user

mysql> CREATE USER 'wordpress'
         IDENTIFIED WITH mysql_native_password
         BY 'ないしょ';

mysql> CREATE DATABASE wordpress;
mysql> GRANT ALL ON wordpress.* TO 'wordpress';

その後の windowsから作成したdatabaseへの接続testの為、 Connector/ODBC を利用すると、よいかと思います。

MySQL :: Download Connector/ODBC

f:id:end0tknr:20220115084100p:plain

step 3 - download wordrecreate & unzip

まず、

から、ダウンロードし、

c:/inetpub/wwwroot/wp

として、解凍してください。

wordpressは、上記dirへの書込みを必要とするようですので、 以下のように権限を付与します。

f:id:end0tknr:20220115084113p:plain

step 4 - edit wp-config.php

install php ver.7.3.15 and wordpress ver.5.3.2 - end0tknr's kipple - web写経開発

↑こちらのentryのように wp-config.php を編集します。

DOS> cd c:/inetpub/wwwroot/wp
DOS> cp wp-config-sample.php wp-config.php

DOS> vi wp-config.php
<?php
define( 'DB_NAME',     'wordpress' );
define( 'DB_USER',     'wordpress' );
define( 'DB_PASSWORD', 'ないしょ' );
define( 'DB_HOST',     '192.168.56.108' );
define( 'DB_CHARSET',  'utf8' );
define( 'DB_COLLATE', '' );

define( 'AUTH_KEY',         'put your unique phrase here' );
define( 'SECURE_AUTH_KEY',  'put your unique phrase here' );
define( 'LOGGED_IN_KEY',    'put your unique phrase here' );
define( 'NONCE_KEY',        'put your unique phrase here' );
define( 'AUTH_SALT',        'put your unique phrase here' );
define( 'SECURE_AUTH_SALT', 'put your unique phrase here' );
define( 'LOGGED_IN_SALT',   'put your unique phrase here' );
define( 'NONCE_SALT',       'put your unique phrase here' );

$table_prefix = 'wp_';

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', 'c:/inetpub/wwwroot/wp/wp_errors.log' );

/* カスタム値は、この行と「編集が必要なのはここまでです」の行の間に追加してください。 */

/* 編集が必要なのはここまで ! WordPress でのパブリッシングをお楽しみください。*/

/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
    define( 'ABSPATH', __DIR__ . '/' );
}

/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';

step 5 - access install.php

後は、ブラウザで install.php へ、アクセスし、少々、設定すれば、完了です

http://localhost/wp/wp-admin/install.php

install postgres 14.1 & postgis 3.2 & mapserver 4.0.5 to windows 11

最後に、上記 3 entry の windows 11版です。

windowsの場合、postgisは、posgresに付属していますし、 mapserverは、ms4w というパッケージがありますので、 インストール自体は、随分と簡単です。

目次

install postgres 14.1 & postgis 3.2

PostGIS on windows10 - Qiita

上記urlの通りです。

まず、https://www.enterprisedb.com/downloads/postgres-postgresql-downloads から、 postgresql-14.1-1-windows-x64.exe をダウンロードし、インストーラを実行して下さい。

このインストーラには、stack builderというツールが付属しており、 postgresのインストール完了後、stack builderが起動しますので、 stack builderより、postgres3.2をインストールできます。

f:id:end0tknr:20220110192701p:plain

f:id:end0tknr:20220110192708p:plain

インストール完了後、やはり付属する pg admin4にて、 postgisが有効な「postgis_31_sample」が create database されていることを確認できます。

f:id:end0tknr:20220110192720p:plain

install mapserver 4.0.5

https://mapserver.org/download.html から、 https://www.ms4w.com/ へ、画面遷移し、 インストーラである ms4w-4.0.5-setup.exe を実行するだけです。

国土交通省にあるGISデータをPostGISへインポート

最後に、国土交通省にあるGISデータをPostGISへインポート(2022年版) - end0tknr's kipple - web写経開発 と 同様の作業を windows版でも行います。

GISデータのインポート

上記entryで使用したものと殆ど同じコマンドを power shell で実行します。

PS> & 'C:\Program Files\PostgreSQL\14\bin\psql.exe' \
          -U postgres -f create_gyosei_kuiki.sql postgis_31_sample
PS> & 'C:\Program Files\PostgreSQL\14\bin\psql.exe' \
          -U postgres -f insert_gyosei_kuiki.sql postgis_31_sample

mapファイルの作成と、画像への出力

画像への出力には、shp2img.exe を使用しますが、 ms4wのインストール直後の状態では、依存するdllを見つけられない為、 まず、 c:/ms4w/tools/mapserv/shp2img.exe から c:/ms4w/Apache/cgi-bin/shp2img.exe へ、コピーします。

PS> & C:\ms4w\Apache\cgi-bin\shp2img.exe -m .\gyosei_kuiki.map -o .\gyosei_kuiki.png

その上で、power shellで↑このように実行すると、↓このようにpngが作成されます

f:id:end0tknr:20220110192618p:plain

国土交通省にあるGISデータをPostGISへインポート(2022年版)

「更に」先程の上記entryの続き & 前回2017年の上記entryの2022年版です。

GISデータのダウンロード & 解凍

http://nlftp.mlit.go.jp/ksj/index.html

2017年と比較すると、画面構成や zipファイルの名称が変更されていますが、 上記urlより、行政区域面 (東京 N03-20210101_13_GML.zip)をダウンロード。

$ unzip N03-20210101_13_GML.zip
$ ls -lh N03-20210101_13_GML
total 47M
-rw-rw-r-- 1 end0tknr end0tknr  12K Mar  9  2021 KS-META-N03-21_13_210101.xml
-rw-rw-r-- 1 end0tknr end0tknr 459K Feb 25  2021 N03-21_13_210101.dbf
-rw-rw-r-- 1 end0tknr end0tknr  21M Mar  3  2021 N03-21_13_210101.geojson
-rw-rw-r-- 1 end0tknr end0tknr  145 Feb 25  2021 N03-21_13_210101.prj
-rw-rw-r-- 1 end0tknr end0tknr 7.3M Feb 25  2021 N03-21_13_210101.shp
-rw-rw-r-- 1 end0tknr end0tknr  49K Feb 25  2021 N03-21_13_210101.shx
-rw-rw-r-- 1 end0tknr end0tknr  18M Mar  3  2021 N03-21_13_210101.xml

shapeファイルから、create table文 , insert文作成、更にimport

$ pwd
/home/end0tknr/tmp/GIS/N03-20210101_13_GML
$ /usr/local/pgsql/bin/shp2pgsql -p \
  ./N03-21_13_210101 gyosei_kuiki > ./create_gyosei_kuiki.sql
$ /usr/local/pgsql/bin/shp2pgsql -W cp932 -a \
  ./N03-21_13_210101 gyosei_kuiki > ./insert_gyosei_kuiki.sql

$ /usr/local/pgsql/bin/psql -U postgres gis_test < ./create_gyosei_kuiki.sql
$ /usr/local/pgsql/bin/psql -U postgres gis_test < ./insert_gyosei_kuiki.sql

mapファイルの作成と、画像への出力

$ vi gyosei_kuiki.map

MAP
    SIZE 800 800           #画像size
    EXTENT 138.8 35.5 140 36   #出力範囲の座標
    STATUS ON              #地図を表示するか
    UNITS DD               #地図の単位(DD は緯度経度)
    IMAGECOLOR 255 255 255 #背景色R G B
    IMAGETYPE PNG          #地図画像を保存する形式
    LAYER
         NAME "gyosei"
         CONNECTIONTYPE POSTGIS
         CONNECTION "user=postgres password='' dbname=gis_test host=localhost"
         DATA "geom FROM gyosei_kuiki" #select文
         TYPE LINE
         STATUS ON
         CLASS
             COLOR 0 0 0
         END
    END
END
$ /usr/local/bin/shp2img -m gyosei_kuiki.map -o gyosei_kuiki.png

↑このように実行すると、以下のようなpngが作成されます。

f:id:end0tknr:20220110153731p:plain

install postgis & mapserver from source to postgres 14.1

先程の上記entryの続き & 前回2017年のinstall postgis & mapserver の2022年版です。

2017年に実施した際と異なり、 compilerが依存moduleを上手く見つけられず、 「from source」とタイトルに記載しておきながら、「yum」も使用しており、 結果は怪しい気がします。

目次

postgis

http://postgis.net/source/

Prerequisites

geos

$ wget http://download.osgeo.org/geos/geos-3.10.1.tar.bz2
$ tar -xvf geos-3.10.1.tar.bz2
$ cd geos-3.10.1
$ less INSTALL.md

$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Release ..
$ make
$ make check
$ sudo make install

$ sudo vi /etc/ld.so.conf
/usr/local/lib64  ## ADD

$ sudo ldconfig

proj

$ wget --no-check-certificate \
  https://www.sqlite.org/2022/sqlite-autoconf-3370200.tar.gz
$ tar -xvf sqlite-autoconf-3370200.tar.gz
$ cd sqlite-autoconf-3370200

$ ./configure \
  --enable-editline --enable-readline --enable-session --enable-debug
$ make
$ sudo make install
$ sudo yum install libtiff-devel
$ wget --no-check-certificate \
  https://download.osgeo.org/proj/proj-8.2.0.tar.gz
$ tar -xvf proj-8.2.0.tar.gz
$ cd proj-8.2.0

$ export SQLITE3_LIBS="-L/usr/local/lib -lsqlite3"

$ ./configure
$ make
$ make check
$ sudo make install

GDAL

wget https://github.com/OSGeo/gdal/releases/download/v3.4.1/gdal-3.4.1.tar.gz
tar -xvf gdal-3.4.1.tar.gz
cd gdal-3.4.1
./configure --without-sqlite3 ※1
make
sudo make install

※1 make時に以下のエラーが表示され、※2を参考に sqlite の configure オプションを変更したものの、 解消しなかった為、「--without-sqlite3」を付加しています。

$ make
 :
/home/end0tknr/tmp/gdal-3.4.1/.libs/libgdal.so: undefined reference to `sqlite3_column_origin_name'
/home/end0tknr/tmp/gdal-3.4.1/.libs/libgdal.so: undefined reference to `sqlite3_column_table_name'
collect2: error: ld returned 1 exit status
make[1]: *** [gdalinfo] Error 1
make[1]: Leaving directory `/home/end0tknr/tmp/gdal-3.4.1/apps'
make: *** [apps-target] Error 2

※2 - refer to https://www.sqlite.org/compile.html#enable_column_metadata - https://ytyaru.hatenablog.com/entry/2021/03/05/000000

JSON-C

$ yum install json-c-devel

$ wget https://github.com/json-c/json-c/archive/refs/tags/json-c-0.15-20200726.tar.gz

less README.md

$ mkdir json-c-build
$ cd json-c-build
$ cmake ..
$ make
$ make test
$ sudo make install

libxml2-devel

$ sudo yum install libxml2-devel

postgis

$ wget --no-check-certificate \
  https://download.osgeo.org/postgis/source/postgis-3.2.0.tar.gz


$ tar -xvf postgis-3.2.0.tar.gz
$ cd postgis-3.2.0
$ ./configure \
    --with-pgsql=/usr/local/pgsql/bin/pg_config \
    --with-pgconfig=/usr/local/pgsql/bin/pg_config \
    --without-protobuf
$ make
$ sudo make install


$ /usr/local/pgsql/bin/createdb -U postgres -E utf8 gis_test
$ /usr/local/pgsql/bin/psql -U postgres -d gis_test \
    -f /usr/local/pgsql/share/contrib/postgis-3.2/postgis.sql
$ /usr/local/pgsql/bin/psql -U postgres -d gis_test \
    -f /usr/local/pgsql/share/contrib/postgis-3.2/spatial_ref_sys.sql

mapsserver

http://mapserver.org/installation/unix.html

Prerequisites

libpng

$ wget --no-check-certificate \
$   https://download.sourceforge.net/libpng/libpng-1.6.37.tar.gz
$ tar -xvf libpng-1.6.37.tar.gz
$ cd libpng-1.6.37
$ ./configure LDFLAGS="-L/usr/local/lib -lz" ※1
$ make
$ make check
$ sudo make install

※1 make時に以下のerrorとなる為、LDFLAGSを追加

$ make
 :
./.libs/libpng16.so: undefined reference to `inflateValidate'
collect2: error: ld returned 1 exit status
make[1]: *** [pngfix] Error 1
make[1]: Leaving directory `/home/end0tknr/tmp/libpng-1.6.37'
make: *** [all] Error 2

freetype

$ wget --no-check-certificate \
  https://download.savannah.gnu.org/releases/freetype/freetype-2.11.1.tar.gz
$ tar -xvf freetype-2.11.1.tar.gz
$ cd freetype-2.11.1
$ ./configure
$ make
$ sudo make install

libjpeg

$ wget http://www.ijg.org/files/jpegsrc.v9d.tar.gz
tar -xvf jpegsrc.v9d.tar.gz
cd jpeg-9d
./configure
make
make check
sudo make install

FriBidi

sudo yum install libtool

$ wget https://github.com/fribidi/fribidi/archive/refs/tags/v1.0.11.tar.gz
$ tar -xvf v1.0.11.tar.gz
$ cd fribidi-1.0.11
$ ./autogen.sh
$ ./configure
$ make
$ make check
$ sudo make install

cario

$ wget --no-check-certificate \
  https://www.cairographics.org/releases/cairo-1.16.0.tar.xz
$ tar -xvf cairo-1.16.0.tar.xz
$ cd cairo-1.16.0

$ ./configure
  :
checking for cairo's PNG functions feature... 
configure: WARNING: Could not find libpng in the pkg-config search path
checking whether cairo's PNG functions feature could be enabled... no
configure: error: recommended PNG functions feature could not be enabled

$ sudo yum install libpng-devel  ※1
$ sudo yum install libpng-pixman
$ sudo yum install freetype-devel

$ ./configure
$ make
$ make check ※2
$ sudo make install

※1 libpng等は、sourceから install 済でしたが、 cairoがこれを見つけられない為、sudo yum install しました。

※2 make checkでは、failがありましたが、無視して make installしました。

harfbuzz

2022/1時点の最新は、ver.3.2.0ですが、make時にerrorとなった為、 ver.2系を使用しています。

$ wget https://github.com/harfbuzz/harfbuzz/archive/refs/tags/2.9.1.tar.gz
$ cd harfbuzz-3.2.0
$ ./autogen.sh
$ ./configure
$ make
$ make check
$ sudo make install

mapserver

$ sudo yum install harfbuzz-devel

$ wget --no-check-certificate \
  https://download.osgeo.org/mapserver/mapserver-7.6.4.tar.gz
$ tar -zxvf mapserver-7.6.4.tar.gz
$ cd mapserver-7.6.4

$ less INSTALL.CMAKE

$ mkdir build
$ cd build

$ cmake -DCMAKE_PREFIX_PATH=/usr/local/pgsql \
        -DWITH_PROTOBUFC=0 \
        -DWITH_GIF=0 \
    -DWITH_FCGI=0 \
        ..
$ make
$ sudo make install

install postgres 14.1 from source to cent 7.9

install postgres 12.3 from source code to centos8 - end0tknr's kipple - web写経開発

以前のentryの2022年版です。

目次

事前準備

$ sudo yum install systemd-devel

postgresのinstall

$ wget --no-check-certificate \
  https://ftp.postgresql.org/pub/source/v14.1/postgresql-14.1.tar.gz

$ tar -xvf postgresql-14.1.tar.gz
$ cd postgresql-14.1
$ less INSTALL

$ ./configure --with-systemd
$ make
$ make check
$ su
# make install
# adduser postgres
# mkdir /usr/local/pgsql/data
# chown postgres /usr/local/pgsql/data

postgresの設定?

# su - postgres
$ /usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data
$ /usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data -l logfile start

$ /usr/local/pgsql/bin/createdb test
$ /usr/local/pgsql/bin/psql test

自動起動

$ sudo vi /etc/systemd/system/postgresql.service

[Unit]
Description=PostgreSQL database server
Documentation=man:postgres(1)

[Service]
Type=notify
User=postgres
ExecStart=/usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data
ExecReload=/bin/kill -HUP $MAINPID
KillMode=mixed
KillSignal=SIGINT
TimeoutSec=0

[Install]
WantedBy=multi-user.target

$ sudo systemctl enable postgresql
Created symlink /etc/systemd/system/multi-user.target.wants/postgresql.service → /etc/systemd/system/postgresql.service.
$ sudo systemctl start postgresql

iis for win11 に fastcgi な php 環境の構築

目次

php 7.4 の install

php for win の ダウンロード & 解凍

DOS> wget https://windows.php.net/downloads/releases/php-7.4.27-nts-Win32-vc15-x64.zip
DOS> unzip php-7.4.27-nts-Win32-vc15-x64.zip
DOS> mv php-7.4.27-nts-Win32-vc15-x64 C:\php

php.ini 作成

http://mztm.jp/2017/10/12/windows10iisphp/ にあるものをコピーし、 php.ini の内容は理解していません。

DOS> cd C:\php
DOS> cp php.ini-production php.ini
DOS> vi php.ini

extension_dir = "ext"
cgi.force_redirect = 0
cgi.fix_pathinfo = 1
fastcgi.impersonate = 1
fastcgi.logging = 0
extension=php_mbstring.dll
extension=php_mysqli.dll
extension=php_odbc.dll
mbstring.language = Japanese
mbstring.internal_encoding = UTF-8
mbstring.http_input = auto
mbstring.http_output = UTF-8
mbstring.encoding_translation = On
mbstring.detect_order = auto

システム環境変数:PATHに追加

f:id:end0tknr:20220109074658p:plain

iis for win 11の有効化

「プログラムのアンインストールまたは変更」画面から 「Windowsの機能の有効化または無効化」画面へ遷移し、設定します。

その後、ブラウザで http://localhost へアクセスし、画面表示されれば、OKです。

f:id:end0tknr:20220109075841p:plain

f:id:end0tknr:20220109075854p:plain

iis 設定

モジュールマップ追加

「インターネット インフォメーション サービス(IIS) マネージャー」より 「FastCgiModule」を追加してください。

f:id:end0tknr:20220109080500p:plain

f:id:end0tknr:20220109080511p:plain

既定のドキュメント追加

apacheの directory indexに該当しますので、index.php を追加して下さい。

f:id:end0tknr:20220109092903p:plain

f:id:end0tknr:20220109092912p:plain

接続テスト

c:/inetpub/wwwroot の権限変更

c:/inetpub/wwwroot の書込み権限は、defaultでは、管理者以外にありませんので、 「フルコントロール」「変更」を追加してください。

f:id:end0tknr:20220109081315p:plain

test.php の配備と、接続テスト

いつもの?ように phpinfo() を配備し、これにアクセスして、表示されれば、完了です。

<?php
phpinfo();
?>

f:id:end0tknr:20220109081326p:plain

2022年版 install mysql 8 from source to cent 7.9

目次

参考url

依存package install

$ sudo yum install openssl-devel
$ sudo yum install ncurses-devel
$ sudo yum install libedit-devel
$ sudo yum install boost-devel
$ sudo yum install gcc-c++
$ sudo yum install centos-release-scl
$ sudo yum install devtoolset-10
$ scl enable devtoolset-10 bash
$ wget https://github.com/Kitware/CMake/releases/download/v3.21.0/cmake-3.21.0.tar.gz
$ tar -xvf cmake-3.21.0.tar.gz
$ cd cmake-3.21.0
$ ./configure
$ make
$ make test
$ sudo make install

mysql install

$ wget https://downloads.mysql.com/archives/get/p/23/file/mysql-boost-8.0.27.tar.gz
$ tar -xvf mysql-boost-8.0.27.tar.gz
$ cd mysql-8.0.27
$ mkdir build
$ cd build

$ /usr/local/bin/cmake .. \
   -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \
   -DDEFAULT_CHARSET=utf8 \
   -DDEFAULT_COLLATION=utf8_general_ci \
   -DENABLED_LOCAL_INFILE=true \
   -DWITH_INNOBASE_STORAGE_ENGINE=1 \
   -DWITH_EXTRA_CHARSETS=all \
   -DWITH_BOOST=../boost \
   -DWITH_SYSTEMD=ON \
   -DWITH_ZLIB=system -DWITH_SSL=system \
   -DWITH_EDITLINE=system
$ make
$ make test
$ sudo make install

config mysql

$ sudo groupadd mysql
$ sudo useradd -r -g mysql mysql

以下のmy.cnf は、以前の https://end0tknr.hateblo.jp/entry/20190602/1559470417 を 参考にしています。

$ sudo vi /etc/my.cnf

# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.6/en/server-configuration-defaults.html

[mysqld]
max_allowed_packet = 32M
innodb_log_file_size = 128MB
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M

# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin

# These are commonly set, remove the # and set as required.
# basedir = .....
# datadir = .....
# port = .....
# server_id = .....
# socket = .....
basedir = /usr/local/mysql
datadir = /var/mysql_data

skip-grant-tables

default_password_lifetime=0

# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M 

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

以下の「mysqld --initialize --user=mysql」の際、 mysql root用パスワードが表示されますが、 今回の場合、my.cnf で skip-grant-tables を使用していますので PWなしで接続できます。

$ sudo mkdir /var/mysql_data
$ sudo chown mysql:mysql /var/mysql_data
$ sudo chmod 750 /var/mysql_data

$ sudo /usr/local/mysql/bin/mysqld --initialize --user=mysql
  :
A temporary password is generated for root@localhost: m0&kd0W0q,Ez

$ sudo /usr/local/mysql/bin/mysql_ssl_rsa_setup

自動起動

$ sudo cp /home/end0tknr/tmp/mysql-8.0.27/build/scripts/mysqld.service \
    /etc/systemd/system/
$ sudo systemctl enable mysqld.service
$ sudo systemctl start mysqld.service

root パスワードの変更

step1 - skip-grant-tables で、パスワードなし接続を有効化

$ sudo vi /etc/my.cnf

skip-grant-tables

$ sudo systemctl stop mysqld.service
$ sudo systemctl start mysqld.service

step2 - rootパスワードを null 化

$ /usr/local/mysql/bin/mysql -u root

mysql> use mysql;
mysql> UPDATE mysql.user SET authentication_string=null WHERE User='root';

step3 - skip-grant-tables で、パスワードなし接続を無効化

$ sudo vi /etc/my.cnf
#skip-grant-tables

$ sudo systemctl stop mysqld.service
$ sudo systemctl start mysqld.service

step4 - rootパスワードを設定

$ /usr/local/mysql/bin/mysql -u root

mysql> ALTER USER 'root'@'localhost' identified BY 'ないしょ';

先程、設定したパスワードで接続テスト

$ /usr/local/mysql/bin/mysql -u root -p

他ユーザやデータベースの作成

mysql> CREATE USER 'wordpress'
         IDENTIFIED WITH mysql_native_password
         BY 'wordpress';

mysql> CREATE DATABASE wordpress;
mysql> GRANT ALL ON wordpress.* TO 'wordpress';

BeautifulSoup for python で suumo の 物件詳細取得

selenium + chromedriver.exe + python で suumo の 物件詳細取得 - end0tknr's kipple - web写経開発

先程、上記entryを記載しましたが、 selenium の場合、動作があまりに遅い...

今回の場合、画面に対し click 等の操作が不要ですので、 改めて BeautifulSoup for python で記載しました。

#!python3
# -*- coding: utf-8 -*-

from bs4 import BeautifulSoup
import requests
import csv
import re
import sys
import time

disp_keys = [
    'base_url','物件名', '販売価格', '所在地','沿線・駅',
    '間取り','建物面積','専有面積','土地面積'
]

conf = {
    "retry_limit" : 10,
    "retry_sleep" : 10,
}


def main():
    
    urls_list_tsv = sys.argv[1]
    fh = open(urls_list_tsv, 'r', encoding='UTF-8')

    i = 0
    for tsv_line in fh:
        i += 1
        if i % 50 == 0:
            print(i, file=sys.stderr,flush=True)
        else:
            print(".", end="",file=sys.stderr,flush=True)

        tsv_line = tsv_line.strip()
        (base_url, pref, result_url) = tsv_line.split("\t")

        # 新築マンションは価格等が記載されていないことが多い為、無視
        if base_url == "https://suumo.jp/ms/shinchiku/":
            continue

        bukken_infos = get_bukken_detail(base_url, pref, result_url)
        
        for bukken_info in bukken_infos:
            disp_bukken_info(bukken_info)

    fh.close()


def get_http_requests(result_url):

    i = 0
    while i < conf["retry_limit"]:
        i += 1
        result = None
        try:
            result = requests.get(result_url)
            return result
        except:
            print("WARN retry requests.get()", result_url ,file=sys.stderr)
            time.sleep(conf["retry_sleep"])

    print("ERROR requests.get()", result_url ,file=sys.stderr)
    return None
        

def get_bukken_detail(base_url, pref, result_url):

    result = get_http_requests(result_url)
    if not result:
        return []

    soup = BeautifulSoup(result.content, 'html.parser')

    bukken_divs = soup.select("div.dottable.dottable--cassette")

    ret_bukken_infos = []
    
    for bukken_div in bukken_divs:
        bukken_info = {'base_url':base_url}
        dls = bukken_div.select("dl")
        for dl in dls:
            dts = dl.select("dt")
            dds = dl.select("dd")
            if len(dts) == 0 or len(dds) == 0:
                continue
            bukken_info[ dts[0].text.strip() ] = dds[0].text.strip()

        ret_bukken_infos.append( bukken_info )
    return ret_bukken_infos


def disp_bukken_info(bukken_info):

    disp_cols = []
    for disp_key in disp_keys:
        if disp_key in bukken_info:
            disp_cols.append( bukken_info[disp_key] )
        else:
            disp_cols.append( "" )

    # refer to https://qiita.com/butada/items/33db39ced989c2ebf644
    disp_cols_str = "\t".join(disp_cols)
    disp_cols_str = disp_cols_str.encode('cp932', "ignore")
    disp_cols_str = disp_cols_str.decode('cp932')
    print( disp_cols_str )
    

if __name__ == '__main__':
    main()

selenium + chromedriver.exe + python で suumo の 物件詳細取得

先程の上記entryの続きです。先程の python script で取得した 検索結果一覧のurlに記載されている物件詳細を取得します。

#!python3
# -*- coding: utf-8 -*-

# http://chromedriver.chromium.org/getting-started
from selenium import webdriver
from selenium.webdriver.support.ui     import WebDriverWait
import os
import re
import sys
import time

chrome_conf = {
    "chrome_driver": os.getcwd() + '\\chromedriver.exe',
    "chrome_options" : [
        "--headless",
        "--enable-logging=False",
        #以下はSSLエラー対策らしい
        "--ignore-certificate-errors",
        "--disable-extensions",
        "--ignore-ssl-errors",
        "--disable-print-preview"],
    "implicitly_wait": 10 }

disp_keys = [
    'base_url','物件名', '販売価格', '所在地','沿線・駅', '間取り','建物面積','専有面積','土地面積'
]


def main():

    urls_list_tsv = sys.argv[1]
    fh = open(urls_list_tsv, 'r', encoding='UTF-8')
    browser = init_browser()

    i = 0
    for tsv_line in fh:
        i += 1
        print(i, file=sys.stderr)

        tsv_line = tsv_line.strip()
        (base_url, pref, result_url) = tsv_line.split("\t")

        # 新築マンションは価格等が記載されていないことが多い為、無視
        if base_url == "https://suumo.jp/ms/shinchiku/":
            continue

        bukken_infos = get_bukken_detail(browser, base_url, pref, result_url)
        
        for bukken_info in bukken_infos:
            disp_bukken_info(bukken_info)

        if i % 20 == 0:
            browser.close()
            browser = init_browser()

    fh.close()
    browser.close()

    

def disp_bukken_info(bukken_info):

    disp_cols = []
    for disp_key in disp_keys:
        if disp_key in bukken_info:
            disp_cols.append( bukken_info[disp_key] )
        else:
            disp_cols.append( "" )

    print( "\t".join(disp_cols) )
    

def get_bukken_detail(browser, base_url, pref, result_url):
    # print(pref, result_url, file=sys.stderr)
    
    browser.get( result_url )

    bukken_divs = \
        browser.find_elements_by_css_selector(
            "div.dottable.dottable--cassette")
    ret_bukken_infos = []
    
    for bukken_div in bukken_divs:
        bukken_info = {'base_url':base_url}
        dls = bukken_div.find_elements_by_css_selector("dl")
        for dl in dls:
            dts = dl.find_elements_by_css_selector("dt")
            dds = dl.find_elements_by_css_selector("dd")
            if len(dts) == 0 or len(dds) == 0:
                continue

            bukken_info[ dts[0].text ] = dds[0].text

        ret_bukken_infos.append( bukken_info )
    return ret_bukken_infos
            
    
def init_browser():
    chopt = webdriver.ChromeOptions()
    
    for option_tmp in chrome_conf["chrome_options"]:
        chopt.add_argument( option_tmp )

    browser = webdriver.Chrome(options = chopt,
                               executable_path=chrome_conf["chrome_driver"])
    # 要素が見つかるまで、最大 ?秒 待つ
    browser.implicitly_wait( chrome_conf["implicitly_wait"] )
    return browser

if __name__ == '__main__':
    main()