ウェブインコ

インコの技術メモ

PHP

ファイル一括置換

<?php
$dir = "/home/hoge/";
while (($file = readdir($dh)) !== false) {
  if (($file=='.')or($file=='..')) { continue; }
  _replace($dir.$file);
}
closedir($dh);
function _replace($path) {
  echo $path . "\n";
  $content = file_get_contents($path);
  $b = array(
    "aaaa",
    "bbbb"
  );
  $a = array(
    "AAAA",
    "BBBB"
  );
  foreach ($b as $k => $v) {
    $content = str_replace($v, $a[$k], $content);
  }
  file_put_contents($path, $content);
}


配列←→json

$arr = json_decode($jsontext, true);
$jsontext = json_encode($arr);


CentOS7 コンポーザーを使えるように
構築することが増えたので。

cd /home/ほにゃらら
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
which composer
→ /usr/local/bin/composer
composer -V
→  Composer version 1.7.3 2018-11-01 10:05:06
この後、インストールするものがあれば、composer.json 作ってそのファイルがある場所で以下。
ls
→ composer.json
composer install
そしたら、その場所にダウンロードされて来ます。
composer.json に何を書けば良いのかは Git にだいたい書いてます。


オブジェクトの宣言
(object) を付けます。

$param = (object)array(
    'id'=>1,
    'serial'=>'d001'
);
error_log(print_r($param->seiral, true), 3, '/home/logs/log');


最後の文字がカンマだったら削除

$likecsv = 'hoge,hage,fuga,';
$csv = rtrim($likecsv, ','); // hoge,hage,fuga
第2引数がなければ以下を削除。
 半角スペース( )、タブ(\t)、改行(\n)、復帰(\r)、NULL バイト(\0)、垂直タブ(\x0B)
先頭からは ltrim() 。
先頭と末尾の両方からは trim() 。


WordPress のデバッグログが出ん(CentOS7)
以下な感じで、wp_config.php を書き換えてもファイル出力されません。
vi wp_config.php

// define('WP_DEBUG', false);
define('WP_DEBUG', true); // WP_DEBUG モードを有効化
if ( WP_DEBUG ) {
  define('WP_DEBUG_LOG', true); // /wp-content/debug.log ファイルへ出力
  define('WP_DEBUG_DISPLAY', false); // 画面への表示を無効化
  @ini_set('display_errors', 0);
}

以下を修正。
vi /etc/php-fpm.d/www.conf
;php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_value[error_log] = /var/log/php-fpm/www-error.log
そしてリスタート。
systemctl restart php-fpm
systemctl restart httpd
/wp-content/debug.log に出力されました。


複数バージョン管理
WordPress がらみで、PHP7.2 が動いているサーバーで PHP5.6 のテスト環境も必要になったので。

// php5.6 インストール
yum install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
yum -y install yum-utils
yum-config-manager --enable remi
yum -y install php56-php-{opcache,pecl-apcu,pecl-memcached}
php56 -v
PHP 5.6.40 (cli) (built: May 13 2020 09:43:09)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies
// 確認
php56 -v
php56 --ini | grep Loaded | awk '{print 56}'

// php-fpm インストール
yum -y install php56-php-fpm
// php-fpm の設定
sed -i '/pm = /s/dynamic/ondemand/' /opt/remi/php56/root/etc/php-fpm.d/www.conf
// 確認
grep 'pm = ondemand' /opt/remi/php56/root/etc/php-fpm.d/www.conf

// listen のポート指定
sed -i "s/9000/9056/" /opt/remi/php$v/root/etc/php-fpm.d/www.conf
// 確認
grep 'listen = 127' /opt/remi/php56/root/etc/php-fpm.d/www.conf

// Apache の設定
vi /etc/httpd/conf.d/vhosts.conf
<VirtualHost *:80>
  ServerName honyarara.com
  ServerAlias www.honyarara.com
  DocumentRoot "/home/com.honyarara.www/public_html"
  ErrorLog  /home/com.honyarara.www/logs/error_log
  CustomLog /home/com.honyarara.www/logs/access_log combined
  RewriteEngine on
  AddDefaultCharset UTF-8
  <Directory "/home/com.honyarara.www/public_html">
    Options +ExecCGI
    AddHandler cgi-script .pl .cgi .py
    Options All
    AllowOverride All
# HTML 取り込み
    AddOutputFilter INCLUDES .html
    SSILegacyExprParser on
  </Directory>
# PHP バージョン指定 ← ここ
  <FilesMatch \.php$>
    SetHandler "proxy:fcgi://127.0.0.1:9056"
  </FilesMatch>
</VirtualHost>

// 再起動
systemctl restart php56-php-fpm
systemctl restart php-fpm
systemctl restart httpd

// 確認
vi /home/com.honyarara.www/public_html/info.php
<?php phpinfo(); ?>
必要ならPCの hosts を修正
C:\Windows\System32\drivers\etc\hosts
99.99.99.999 www.honyarara.com
99.99.99.999 honyarara.com
(99.99.99.999 はサーバーの IP)

http://honyarara.com/info.php


pタグの中の brタグをなんとか
$data = '<p>1111<br>2222<br>3333</p>4444<br>5555'."\n";
$data .= '<p class="hoge">6666<br>7777<br>8888</p>9999<br>0000';
$res = preg_replace_callback('/(<p>|(<p )(.*?)<\/p>/is'
  , function($matches) {
// return preg_replace('/<br>|<br \/>/', '', $matches[0]); // 削除
  return preg_replace('/<br>|<br \/>/', '</p><p>', $matches[0]); // pでくるむ
}
  , $data
);

複数行を 1行とみなして置き換え
s 付けるだけです。

// $lines 複数行の文字列
$res = preg_replace('/ほにゃらら/s', '置き換え後の文字', $lines);


環境変数
vhosts.conf 側
  </Directory>
  SetEnv AAAA "warosu"
</VirtualHost>
PHP 側
  $db = getenv(AAAA');

ハッシュの配列をソート
例)こういうのを position で並べ替えたいとき
$hashArray['Model'] = array(
array('id'=>'1', 'name'=>'hoge', 'position'=>'30'),
array('id'=>'2', 'name'=>'fuga', 'position'=>'10'),
array('id'=>'3', 'name'=>'hage', 'position'=>'20'),
);

foreach ($hashArray['Model'] as $key => $val){$key_position[$key] = $val['position'];}
array_multisort($key_position, SORT_ASC, $hashArray);
print_r($hashArray);

金額
echo number_format(9999);

前ゼロ取る
$day = '01';
echo ltrim($day, '0'); // 文字列操作、左の0取る。
echo intval($day, 10); // 数値に変換、10進数にする。

コマンドラインで動かすとき
which php で確認すること。
/usr/bin/php
のつもりが
/usr/local/bin/php
になってたりして、ツボることうけあい。
(xmlrpc_encode_requestが動かないで悩んだ in さくらVPS)

マッチ
preg_match("/パターン/", 調べる文字列);
"/パターン/"  //文字列の1行目のみを調べる
"/パターン/g"  //複数行を調べる
"/パターン/s"  //改行文字を無視し、1行とみなして調べる
"/パターン/i"  //文字列の大文字・小文字を区別しない
"/パターン/is"  //大文字・小文字を区別せず、1行とみなして調べる
preg_match("/a/", $string);
preg_match("/^a/", $string);
preg_match("/a$/", $string);
行の先頭の 「a」 にマッチ(改行文字が現れる度に次の文字を調べる)
preg_match("/^a/g", $string);
・1-3個続き
preg_match("/a{1,3}/", $string);
・3個以上
preg_match("/a{3,}/", $string);

今月のカレンダー
$monthData = array();
// 月初の曜日
$firstday = date("Ym01", time());
$firstday = strtotime($firstday);
$firstweek = date("w", $firstday);
// 前月端数
if(!empty($firstweek)){
 $preMonthDay = date('d', mktime(0, 0, 0, date('m'), 0, date('Y')));
 $preMonthDate = date('Ymd', mktime(0, 0, 0, date('m'), 0, date('Y')));
 for($i=$firstweek; $i>0; $i-- ){
  $monthData['day'][] = $preMonthDay - $i;
  $monthData['date'][] = $preMonthDate - $i;
 }
}
// 今月
$nowMonthDay = date('d', mktime(0, 0, 0, date('m') + 1, 0, date('Y')));
$nowMonthDate = date('Ym', mktime(0, 0, 0, date('m') + 1, 0, date('Y')));
for($i=1; $i<=$nowMonthDay; $i++ ){
 $monthData['day'][] = $i;
 $monthData['date'][] = $nowMonthDate.sprintf('%02d', $i);
}
// 次月端数
$countDays = count($monthData['day']);
$nextMonthDays = 7 - ($countDays % 7);
if(!empty($nextMonthDays)){
 $nextMonthDate = date('Ym', mktime(0, 0, 0, date('n') + 1, date('j'), date('Y')));
 for($i=1; $i<=$nextMonthDays; $i++ ){
  $monthData['day'][] = $i;
  $monthData['date'][] = $nextMonthDate.sprintf('%02d', $i);
 }
}

サーバーが触らせてもらえなくてなんだか文字化けする時の文字コードの指定。
index.php とか、phpファイルの頭に以下を記述。
ini_set('default_charset', 'SJIS');

改行とか
改行→br
echo nl2br($hoge);
html→エンティティ
echo htmlspecialchars($hoge);
合わせて
echo nl2br(h($hoge));

複数のファイルを同時にダウンロードさせる
プログラムでファイルをウェブルートではない場所から読み込んでダウンロードさせる方法だと、重たいファイルを同時にダウンロードできない。
どうも同一セッションだとマルチには動かず、後の方が待ちきれなくなったり、先の方が切られたりして、いずれにせよエラーになることがある。

session_destroy();
セッションを破棄したらできました。
プログラム開始時に何かしら認証処理があれば、そこからダウンロードまでの間にセッションを破棄すればよいかと。
(大元の方のページがログアウト状態になるかもだけど、それはそれ)

XML_RSS 空振り
RSSが取れない時があります。
色々調べて分からなかったので、以下な感じで対応。
$rss =& new XML_RSS($rssurl['rss']);
$rss->parse();
$getItems = $rss->getItems();
// 空振りしたら1秒待ってとりなおし(最高20回繰返)
if(empty($getItems[0])){
  $j=0;
  while( $j<20 ){
    sleep(1);
    $rss =& new XML_RSS($rssurl['rss']);
    $rss->parse();
    $getItems = $rss->getItems();
    if(!empty($getItems[0])){$j=999;}
    $j++;
  }
}

PHPをコマンドラインで実行したときの引数
実行
php swfed.php spoob.swf ふな 123467890.swf
要素数
$argc
内容
$argv[0],$argv[1],......
このとき、0番目にはswfed.php(自分自身の名前)が入ります。だから使うのは$argv[1]以降。
上記の場合、$argcは4で$argv[0]=swfed.php,$argv[1]=spoob.swf,$argv[2]=ふな,$argv[3]=123467890.swfになります。

include_path
ライブラリを取り込んでいるところでルートディレクトリをどこで指定しているのかが分からなかった。
各スクリプト、.htaccess、/etc/php.ini まで見て無かったけど、 /etc/php.d/の下に任意のファイルを置いて書いていた。

PHPをアップデートしたらswfed.soとimagick.soのエラーが出た。
tar zxf swfed-0.27.tar.gz
cd swfed-0.27/src/
phpize
./configure
make
できたswfed.soを上書き。
OK
次イメージマジック
yum remove ImageMagick
yum install ImageMagick
ダメ(´・ω・`)
pecl uninstall imagick
yum -y install ImageMagick-devel
pecl install imagick
autodetect
OK

phpizeのインストール
yum -y install php-devel
PHPをソースからコンパイルし直すことなくモジュールを追加できます。

配列のおしりに追加
array_push($array, "val1", "val2");

配列 → CSV
$array = array('a', 'b', c');
$str = implode(",", $array);
或いは
foreach ($res as $val) {
$hoge .= $val['Hoge']['id'].',';
}
$hoge = substr($hoge, 0, (strlen($hoge)-1) );

CSV → 配列
$str = "a,b,c,d";
$array = explode(",", $str);
echo $array[0]; // piece1
echo $array[1]; // piece2

日付
$today = date("Y/m/d l H:i:s");

連想配列でループ
foreach ($hash as $key => $val) {
  print "キー: [" . $key . "] 、値: [" . $val . "] です。";
break; //途中で抜けるときはbreskです。
}

正規表現で置換
例)2個以上のスペースは1つに置換。
$str = 'foo o';
$str = preg_replace('/\s\s+/', ' ', $str);

foo o

ファイルにメッセージを出力
$print_r = print_r($hoge, true);
error_log("===== =====\n", 3, '/home/hoge/logs/php_log');
error_log($print_r, 3, '/home/hoge/logs/php_log');
return true;

xampp1.7でpdoが使えない(PHP + MySQL)
以下からパッチをダウンロードして、
http://windows.php.net/downloads/snaps/php-5.2-win32-VC6-x86-latest.zip
\xampp\apache\bin と \xampp\php に libmysql.dll をコピーする。
勿論もとのやつは保存しておくこと。

頭に0を付けてケタ揃え、前ゼロ
$j=sprintf("%05d",$j);

セッションファイルを別の場所に保存したい
バーチャルホストなんかでセッションファイルを分けときたい時。
以下の一行を書いた .htaccess を変えたいディレクトリに置きます。
php_value session.save_path "セッションファイルの保存場所"
例)
cd /home/hoge/publich_html
cat > .htaccess
php_value session.save_path "/var/lib/php/session/hoge"

SmartyでJavaScriptを書く時
{literal}で挟みます。これでSmartyはただの文字列として処理します。
ex.
<script type="text/javascript"/>
{literal}
if ( location.protocol == 'http:' ){
strServerName = 'http://daikoku.ebis.ne.jp';
} else {
strServerName = 'https://secure2.ebis.ne.jp/ver3';
}{/literal}
</script/>

インストールし直し

cd /usr/local/src/php-4.4.2
vi lfconf.sh
--enable-bcmath を書き足す
make clean
sh lfconf.sh
make
/etc/init.d/httpd stop
make install
/etc/init.d/httpd start

インストール用にこんなかんじのファイル作っとくと便利
lfconf.sh という名前で保存して sh lfconf.sh

#!/bin/sh
./configure --enable-mbstring --enable-mbregex --with-dbase=yes --with-mysql --enable-track-vars --enable-discard-path --with-pear --with-config-file-path=/etc/httpd/conf --disable-debug --enable-debug=no --enable-ftp --enable-sockets --enable-mailparse --enable-trans-sid --with-apxs2=/usr/local/apache2/bin/apxs --with-gettext --with-zlib --with-gd --with-jpeg-dir=/usr/lib \
--with-freetype --with-png \
--with-pgsql \
--with-ttf --enable-gd-native-ttf --enable-gd-jis-conv \
--enable-exif \
--enable-memory-limit \
--enable-bcmath
#--enable-zend-multibyte

関数
private:そのクラスからしかアクセスできない
protected:そのクラスと、サブクラスからしかアクセスできない
public:どこからでもアクセスできる

テスト表示
info.php とでもして以下を記述しアップする。
<?php phpinfo(); ?>