MySQL8 でベースにする文字コードはutf8mb4_unicode_ci

照合順序(COLLATION)とは

照合順序は文字列の比較やソート順のルールのことです。各キャラクタセットごとに照合順序が定義されています。

-- SHOW COLLATIONS で一覧が見れる
mysql> SHOW COLLATIONS;
+----------------------------+----------+-----+---------+----------+---------+---------------+
| Collation                  | Charset  | Id  | Default | Compiled | Sortlen | Pad_attribute |
+----------------------------+----------+-----+---------+----------+---------+---------------+
| armscii8_bin               | armscii8 |  64 |         | Yes      |       1 | PAD SPACE     |
| armscii8_general_ci        | armscii8 |  32 | Yes     | Yes      |       1 | PAD SPACE     |
| ascii_bin                  | ascii    |  65 |         | Yes      |       1 | PAD SPACE     |
| ascii_general_ci           | ascii    |  11 | Yes     | Yes      |       1 | PAD SPACE     |
| big5_bin                   | big5     |  84 |         | Yes      |       1 | PAD SPACE     |
| big5_chinese_ci            | big5     |   1 | Yes     | Yes      |       1 | PAD SPACE     |
| binary                     | binary   |  63 | Yes     | Yes      |       1 | NO PAD        |
<snip>

MySQL 8.0 で、utf8mb4 の照合順序が増えました。以下の表で太字にしたものが、新規に追加されたものです。各文字列が、同一と扱われる場合は、○としています。
ci/csCase [In]sensitive の略で、asAcent SensiteveksKatakana Sensitive の略です。

COLLATION A、a はは、ぱぱ はは、ハハ びょういん、びよういん 🍣、🍺 +、+
utf8mb4_bin × × × × × ×
utf8mb4_0900_bin × × × × × ×
utf8mb4_unicode_ci
utf8mb4_general_ci × × × ×
utf8mb4_unicode_520_ci ×
utf8mb4_0900_ai_ci ×
utf8mb4_0900_as_ci × ×
utf8mb4_ja_0900_as_cs × × × ×
utf8mb4_ja_0900_as_cs_ks × × × × ×

アルファベットの大文字・小文字を区別しない要件で、どれが選ばれそうか・・・
utf8mb4_0900_as_ci は「びょういん」「びよういん」が同一と扱われてしまい、いまいちに感じます。

そもそも、日本語の文字列比較やソート結果を網羅的に精査するのは現実的に可能なんでしょうか(上記の表以外にも考えないといけない、パターンがありそうです)。日本語には異字体・長音記号・漢数字・・・ちょっと思いつくだけでも、扱いに悩みそうな要素が多くあります。

絵文字が区別できないとは言え、utf8mb4_general_ci にはずっと使ってきた実績と安心があります。
MySQL 8.0 でも utf8mb4_general_ci を 引き続き使うケースが多いのではないでしょうか。

MySQL 8.0 で utf8mb4_general_ci を使うときの注意点

ALTER TABLE CONVERT TO 時に COLLATION の指定が必要

MySQL 8.0 で utf8mb4 のデフォルトの照合順序が utf8mb4_general_ci から utf8mb4_0900_as_ci に変更になりました。

あわせて、従来の3バイトUTF8、utf8(mb3) は deprecated になっています。
utf8mb4 に変換するときに COLLATE を明示的に指定しないと、utf8_general_ci から utf8mb4_0900_ai_ci へとテーブルのデフォルト照合順序になってしまいます。

mysql> SELECT * FROM utf8t WHERE c1 = "ぱぱ";
Empty set (0.00 sec)

mysql> ALTER TABLE utf8t CONVERT TO CHARACTER SET 'utf8mb4';
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

-- 「ぱぱ」で「はは」がヒットしてしまう
mysql> SELECT * FROM utf8t WHERE c1 = "ぱぱ";
+----+--------+
| pk | c1     |
+----+--------+
|  1 | はは   |
+----+--------+
1 row in set (0.00 sec)

mysql> SHOW CREATE TABLE utf8t \G
*************************** 1. row ***************************
       Table: utf8t
Create Table: CREATE TABLE `utf8t` (
  `pk` bigint unsigned NOT NULL AUTO_INCREMENT,
  `c1` varchar(255) DEFAULT NULL,
  UNIQUE KEY `pk` (`pk`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

このように、COLLATE を指定してALTERする必要があります。

mysql> ALTER TABLE utf8t CONVERT TO CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci';
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql>  SHOW CREATE TABLE utf8t \G
*************************** 1. row ***************************
       Table: utf8t
Create Table: CREATE TABLE `utf8t` (
  `pk` bigint unsigned NOT NULL AUTO_INCREMENT,
  `c1` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
  UNIQUE KEY `pk` (`pk`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
1 row in set (0.00 sec)

SET NAMES では COLLATE の指定が必要

同様に、SET NAMES で照合順序を明示的に指定していない場合、MySQL 8.0 からは utf8mb4_0900_as_ci が使われてしまいます。

# MySQL 8.0 以降は utf8mb4_0900_as_ci が使われる
mysql> SET NAMES utf8mb4;

# MySQL 8.0 以降は 明示的に utf8mb4_general_ci を指定する必要がある。
mysql> SET NAMES utf8mb4 COLLATE utf8mb4_general_ci;

Unknown collation: ‘utf8mb4_unicode_520_ci’

原因は移行先サーバーのMySQLがMySQL5.5以下であるためです。例えば某Sサーバーなど..。utf8mb4_unicode_520_ciというcollationはMySQL5.6以上でしか利用できません。
現行のWordPressはutf8mb4_unicode_520_ciが使用できるサーバーではutf8mb4_unicode_520_ciを優先的に使用してインストールを行います。charsetとcollationを決定するwp-db.phpのコードは以下のようになっています。

	/**
	 * Determines the best charset and collation to use given a charset and collation.
	 *
	 * For example, when able, utf8mb4 should be used instead of utf8.
	 *
	 * @since 4.6.0
	 * @access public
	 *
	 * @param string $charset The character set to check.
	 * @param string $collate The collation to check.
	 * @return array The most appropriate character set and collation to use.
	 */
	public function determine_charset( $charset, $collate ) {
		if ( ( $this->use_mysqli && ! ( $this->dbh instanceof mysqli ) ) || empty( $this->dbh ) ) {
			return compact( 'charset', 'collate' );
		}

		if ( 'utf8' === $charset && $this->has_cap( 'utf8mb4' ) ) {
			$charset = 'utf8mb4';
		}

		if ( 'utf8mb4' === $charset && ! $this->has_cap( 'utf8mb4' ) ) {
			$charset = 'utf8';
			$collate = str_replace( 'utf8mb4_', 'utf8_', $collate );
		}

		if ( 'utf8mb4' === $charset ) {
			// _general_ is outdated, so we can upgrade it to _unicode_, instead.
			if ( ! $collate || 'utf8_general_ci' === $collate ) {
				$collate = 'utf8mb4_unicode_ci';
			} else {
				$collate = str_replace( 'utf8_', 'utf8mb4_', $collate );
			}
		}

		// _unicode_520_ is a better collation, we should use that when it's available.
		if ( $this->has_cap( 'utf8mb4_520' ) && 'utf8mb4_unicode_ci' === $collate ) {
			$collate = 'utf8mb4_unicode_520_ci';
		}

		return compact( 'charset', 'collate' );
	}

 

対策・解決方法

インポートするSQLファイルをエディタで開き、以下のように置き換えます。

utf8mb4_unicode_520_ci → utf8_general_ci

utf8mb4 → utf8

[参考]

https://stackoverflow.com/questions/29916610/1273-unknown-collation-utf8mb4-unicode-ci-cpanel/29939906#29939906

 

Strict Standards エラーを非表示にできない EC-CUBE2.4系

configファイルで ’error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);’と書いても効果なしでした。

/data/class/SC_Initial.php
102行目付近

function setErrorReporting() {
	error_reporting(E_ALL & ~E_NOTICE);
}

ここを書き換えたら Strict Standards エラー が非表示になった。

function setErrorReporting() {
	error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);
}

error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);

error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE);

form に複数ボタンで 異る処理をする(その1)

標準的なformボタン

<form>
  <input type='submit' value='送信'>
</form>

複数ボタンを設置

<form>
  <input type='submit' name='action' value='送信'>
  <input type='submit' name='action' value='下書き保存'>
</form>

ボタンごとに異る処理

if ($_POST['action'] == '送信') {
  // 送信処理
} else if ($_POST['action'] == '下書き保存') {
  // 保存処理
}

2018年以降のサーバーで、EC-CUBE2系を動かすには?

2016〜2018年頃、レンタルサーバーでPHPやSQLのバージョンアップにより
いろんなオープンソースが対応できなくなるケースが多発しています。

EC-CUBE2系の場合、症状は様々ですが
・サイトが表示されない
・インストールが完了できない
・その他

原因の一つとして
SET SESSION storage_engine = InnoDB の実行時に以下のエラーで実行できないケースがあります。

/data/class/db/dbfactory/SC_DB_DBFactory_MYSQL.php の 末尾付近を編集します。

    function initObjQuery(SC_Query &$objQuery) {
        // $objQuery->exec('SET SESSION storage_engine = InnoDB');
	$objQuery->exec('SET SESSION default_storage_engine = InnoDB');
        $objQuery->exec("SET SESSION sql_mode = 'ANSI'");
    }

SQLite3 にPHPで接続する

シンプルに接続

// 基本接続
$dsn ="sqlite:yoga.db";
$pdo = new PDO($dsn);
// SQL文処理
$sql = "select * from tb_shop";
$statement = $pdo->prepare($sql);
$statement->execute();

ループ(レコード)読み込み

// 基本接続
$dsn ="sqlite:yoga.db";
$pdo = new PDO($dsn);
// SQL文処理
$sql = "select * from tb_shop";
$rs = $pdo->prepare($sql);
$rs -> execute();
foreach ($rs->fetchall() as $key => $value) {
	echo '<hr>';
	var_dump($value);
}

エラーチェックなどを行う場合

// SQLite3 に接続
$dsn ="sqlite:yoga.db";
$pdo = new PDO($dsn);
$sqltext = "select * from tb_shop";
$sql = $pdo->prepare($sqltext);
try{
	if(!$sql->execute()){
		echo "Failed(SQL文に問題あり)";
	}
	foreach ($sql->fetchall() as $key => $value) {
		echo "$key:$value[0]<br/>\n";
	}
} catch(Exception $e){
	echo "Failed:(システムエラー)".$e->getMessage();
}

MySQL カラムのコメントを取得する

SQL文の半自動化に、さらなる進化がありました。

MySQLのカラムコメントを抽出することで
フォームの半自動化→7割自動化 を実現しました。

//構文設定
$stmt = $pdo->prepare('SHOW FULL columns FROM ' . wr_user);

//実行
$stmt->execute();

$array_comment = array();
$i = 0;
foreach($stmt->fetchAll() as $result):
	array_push($array_comment, $result['Comment']);
	$i ++;
endforeach;

var_dump($array_comment);

SQL文 を半自動で生成する


$statement = $pdo->query($sql);
$item = $statement->fetch(PDO::FETCH_ASSOC);
$i = 0;
foreach($item as $key => $val){
    if($i == 0){
        $kanma = '';
    }else{
        $kanma = ',';
    }
    $key_text .= $kanma."`".$key."`";
    $val_text .= $kanma."'".$_POST[$key]."'";
    $i ++;
}

echo '<hr>'.$key_text.'<hr>';
echo $val_text.'<hr>';

$sql = "INSERT INTO `tb_staff` ($key_text) VALUES($val_text)";
echo $sql;

$statement = $pdo->query($sql);
$pdo = new PDO('mysql:host = '.DB_SERVER.';dbname='.DB_NAME.';charset=utf8', DB_USER, DB_PASSWORD);
$sql = "SELECT * FROM `wr_user` LIMIT 1";
$statement = $pdo->query($sql);
$item = $statement->fetch(PDO::FETCH_ASSOC);

$i = 0;
foreach($item as $key => $val){

	if($i == 0){
		$kanma = '';
	}else{
		$kanma = ',';
	}

	$key_text .= $kanma."`".$key."`";
	$val_text .= $kanma."'$".$key."'";

	$i ++;
}
echo '<hr>'.$key_text.'<hr>';
echo $val_text.'<hr>';


$sql = "INSERT INTO `wr_user` ($key_text) VALUES($val_text)";
echo $sql;
$db = mysql_connect(DB_HOST.":".DB_PORT,DB_USER,DB_PASSWORD);
// mysql_query("SET NAMES utf8");
mysql_set_charset('utf8');
mysql_select_db(DB_NAME, $db);


$sql = "SELECT * FROM wr_posts LIMIT 1";
$rs = mysql_query($sql,$db);
$item = mysql_fetch_assoc($rs);
var_dump($item);


$i = 0;
foreach($item as $key => $val){

	if($i == 0){
		$kanma = '';
	}else{
		$kanma = ',';
	}

	$key_text .= $kanma."`".$key."`";
	$val_text .= $kanma."'$".$key."'";

	$i ++;
}
echo '<hr>'.$key_text.'<hr>';
echo $val_text.'<hr>';

自動生成の例
INSERT INTO `wr_user`
  (`user_id`,`f1`,`f2`,`f3`)   
  VALUES
  (‘exampleuser_id’,’examplef1′,’examplef2′,’examplef3′)

MySQLのフィールド名をSQL文用に自動で整形する。

MySQLのフィールド名(カラム名)をSQL文用に自動で整形する。

$sql = "SELECT * FROM `dtb_customer` LIMIT 1";
$rs = mysql_query($sql,$db);
$item = mysql_fetch_assoc($rs);
// Key を配列化
$key_arr = array();
foreach($item as $key => $val){
	echo $key."<br>";
}
$sql = "SELECT * FROM `dtb_products` LIMIT 1";
$rs = mysql_query($sql,$db);
$item = mysql_fetch_assoc($rs);
// Key を配列化
$key_arr = array();
foreach($item as $key => $val){
	//      echo $key."=>".$val."<br>"; // 試験表示
	//     array_push($key_arr, $key);
	echo "`".$key."`,";
}

PHP + MySQL で登録時に重複チェックをしたいです。【の対策】

フォームから投げたデータをデータベースに登録する。

多くの人は、リロードすると重複登録されてしまう対策に苦労しています。

いろんな方のお話を聞いていると
いろいろむずかしいことをしている感じです。

でも、本当はとても簡単です。

POSTを消してしまえばいいのです。

$_POST = array();

下記でも消えるはずですが、unset は挙動不審なので、上のようにからの配列にしてしまうと確実で簡単です。

unset($_POST);

ファイルリスト取得PHP

<html xmlns="http://www.w3.org/1999/xhtml" class="wp-toolbar"  lang="ja">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<?php
$dir = './';

$files = scandir($dir);
$files = array_filter($files, function ($file) {
	return !in_array($file, array('.', '..'));
});

$list = array();
$text = '';
foreach ($files as $file) {
	$fullpath = rtrim($dir, '/') . '/' . $file;
	if (is_file($fullpath)) {
		$list[] = $fullpath;
	}
	if (is_dir($fullpath)) {
		$list = array_merge($list, getFileList($fullpath));
	}
}

function getFileList($dir) {
    $files = glob(rtrim($dir, '/') . '/*');
    $list = array();
    foreach ($files as $file) {
        if (is_file($file)) {
            $list[] = $file;
        }
        if (is_dir($file)) {
            $list = array_merge($list, getFileList($file));
        }
    }
 
    return $list;
}

for($i = 0; $list[$i] != ''; $i ++){
	$list[$i] = preg_replace("$\.\/$", "", $list[$i]);
	$list[$i] = preg_replace("$\/$", ",", $list[$i]);
	echo $list[$i].'<br>';
}
?>

php(ImageMagick)で EPS, AI 画像に変換する(その3)

EPS, AI をPHPなどプログラムで変換するときのコツを書きます。(その2)

イラストレーター(.ai)
「PDF互換」で透過されていれば、そのまま透過されます。
「PDF互換」で透過されていなければ、そのまま透過されません。
※ ちなみに、「PDF互換なし」で入稿すると、データがありませんと返ってきます。
イラレ入稿には、レイヤは関係ないのです。
レイヤで透かしを入れたとか、レイヤで透過していたとか、印刷ができてから言っても無理なので、ご注意ください。
イラレの場合「レイヤに透過情報が入っている」は無効です。
イラレの場合「PDF互換レイヤに透過情報」が入っていることが重要です。

フォトショップ(.eps)
各レイヤが画像ですので、レイヤごとに一枚の画像ファイルとして出力されます。
吐き出しファイル名を「output.png」と指定すると
output-0.png
output-1.png
output-2.png
output-3.png
output-*.png
というように、沢山のファイルが吐出されます。
ゼロは全レイヤを統合した画像ファイル
それ以降は、レイヤごとに画像化したファイル
です。
レイヤが独立した画像として認識されるので「透過情報」も引き継がれます。

DTP印刷でも、プログラムの自動処理でも、入稿したとおりに透過情報も反映されます。

※ イラレ入稿で透過されないのは、入稿データが透過されていないのです。

 

試しに
私も、入稿データを作ってみました。

フォトショでは透過情報を簡単にきちんと保存できます。
イラレで透過情報をきちんと保存することは、神業くらい難しいようです。
イラレでレイヤ単位で透過しているのは、大概はベクトル情報です。(←NG) 画像情報としてきちんと透過しなければ入稿には反映されません)

↑確認方法は

イラレで保存したデータを、他のソフトで開いてみてください。
それで透過していたら成功です!

php(ImageMagick)で EPS, AI 画像に変換する(その2)

EPS, AI をPHPなどプログラムで変換するときのコツを書きます。(その2)

イラストレーター(.ai)
透過しているか? 透過していないか?(←ここは自己責任)
一枚の画像化されたレイヤ(PDF互換レイヤ)が印刷対象です。
(イラレでしか見れない他のレイヤは無意味ということです)

フォトショップ(.eps)
各レイヤが画像ですので、レイヤごとに一枚の画像ファイルとして出力されます。
レイヤごとに、印刷に使用されます。

ここで、よくあるトラブルが
イラレで透過していたのに、透過していないポスターが何百枚も出来上がってきた。

イラレは「PDF互換の1レイヤ」のみが利用されます。
それが透過していなかったのなら、入稿した人の原因です。

そういう理由で
イラレで入稿した場合「png」で入稿し直してくださいと言われることも多いです。
「イラレのPDF互換」できちんと透過できている場合は、言われません。
「イラレのPDF互換で透過」の難しさを知っている人は、EPSかpngで入稿しています。
なんでイラレはダメなの?
そんな印刷トラブルが多いようです。

次回は、プログラムで、EPS, AIを 自動変換してみます。

php(ImageMagick)で EPS, AI 画像に変換する(その1)

EPS, AI をPHPなどプログラムで変換するときのコツを書きます。

イラストレーター(.ai)
レイヤは、画像ではなくベクトルデータです。
保存の時に「PDF互換」にチェックを入れると、全レイヤを統合した画像データが
一枚目のレイヤとして保存されます。
この一枚のレイヤのみが、印刷に使用されます。
(イラレでしか見れない他のレイヤは無意味ということです)

フォトショップ(.eps)
各レイヤが画像ですので、レイヤごとに一枚の画像ファイルとして出力されます。
レイヤごとに、印刷に使用されます。

みなさんお気づきと思いますが(←そんなこと、知ってるよという人がほとんどだと思います)
↓イラレは画像処理ソフトではないのです。PDF互換の一枚のレイヤ画像のみが利用されます。
http://d.hatena.ne.jp/akane_neko/20130418/1366236806

印刷屋さんが扱う場合も、プログラムで自動処理を行う場合も
全く同じことができます。

印刷屋さんも(.ai)のソフト上で透過していても
『イラレの「PDF互換」で透過』していないものは、透過しないまま印刷されます。
(当然です)

次は、もう少し具体的に説明します。

フォームの入力文字の型をチェック(エンコードで違いあり)

カタカナその他2バイト文字の正規表現はエンコードによって異なるので注意が必要。
正規表現の末尾の「u」があるので、UTF8の場合の例です。


// check
$error = 0;
// email
if(preg_match('/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/iD', $_SESSION['f5'])){
	
}else{
	$error = 1;
	$error_email = '<div class="red">メールアドレスが不正です。</div>';
}
if(!preg_match( "/[\@-\~]/" , $_SESSION[f6])) {
	$error = 1;
	$error_email = '<div class="red">パスワードが不正です。</div>';
}
// password
if($_SESSION[f6] != $_SESSION[f6a]){
	$error = 1;
	$error_pw = '<div class="red">パスワードが一致しません。</div>';
}

if($_SESSION[f6] == ''){
	$error = 1;
	$error_pw = '<div class="red">パスワードを入力してください。</div>';
}

// zip-code 半角数字以外を削除
if($_SESSION[f7] != ''){
	$_SESSION[f7] = preg_replace("/ー|−|―/", "-", $_SESSION[f7]);
	$_SESSION[f7] = preg_replace("/--/", "-", $_SESSION[f7]);
	$_SESSION[f7] = preg_replace('/[^0-9_-]/', '', $_SESSION[f7]);
	$_SESSION[f7] = preg_replace('/[^0-9a-zA-Z]/', '', $_SESSION[f7]);
}
// tel
if($_SESSION[f11] != ''){
	$_SESSION[f11] = preg_replace("/ー|−|―/", "-", $_SESSION[f11]);
	$_SESSION[f11] = preg_replace("/--/", "-", $_SESSION[f11]);
	$_SESSION[f11] = mb_convert_kana($_SESSION[f11], "a", "utf-8");
	$_SESSION[f11] = preg_replace('/[^0-9_-]/', '', $_SESSION[f11]);
}
// 名前カナ
$error_name_kana = '';
if($_SESSION[f3] != ''){
	if(!preg_match("/^[ァ-ヶー]+$/u",$_SESSION[f3])){
		$error = 1;
		$error_name_kana = '<div class="red">カタカナで入力してください。</div>';
	}
}
if($_SESSION[f4] != ''){
	if(!preg_match("/^[ァ-ヶー]+$/u",$_SESSION[f4])){
		$error = 1;
		$error_name_kana = '<div class="red">カタカナで入力してください。</div>';
	}
}
// shop_name
if($_SESSION[f13] != ''){
	if(!preg_match("/^[ァ-ヶー]+$/u",$_SESSION[f13])){
		$error = 1;
		$error_shopname_kana = '<div class="red">カタカナで入力してください。</div>';
	}
}

メールアドレスかどうかをチェックする

フォームに入力されたメールアドレスをチェックする

個人的には正規表現を使うのがおすすめ
むやみに便利な関数を使うと、phpのバージョンアップで動かなくなく可能性が高い

正規表現のパターンマッチで

f(preg_match('/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/iD', $mailaddress)){
     return '正しいメールアドレスです';
}else{
     return '正しくないメールアドレスです';
}

filter_var関数で

if(filter_var($mailaddress, FILTER_VALIDATE_EMAIL)){
     return '正しいメールアドレスです';
}else{
     return '正しくないメールアドレスです';
}

filter_var関数の方がソースコードが短縮できるように見えるが、
関数を読み込んで処理されるまでの見えない部分を考慮すれば
圧倒的に正規表現のほうがロスが少ない。

SQLデータベースに接続の基本コード

php5〜php7

Database に接続

$pdo = new PDO('mysql:host='.DB_SERVER.';dbname='.DB_NAME.';charset=utf8', DB_USER, DB_PASSWORD);

ヒットがユニークの場合

$sql = "SELECT * FROM `tb_hogehoge`";
$statement = $pdo->query($sql);
$item = $statement->fetch(PDO::FETCH_ASSOC);
var_dump($item);

Roop の場合

$sql = "SELECT * FROM `tb_hogehoge`";
foreach($pdo->query($sql) as $item) {
	var_dump($item);
}

↓php7 から使えなくなる。

$db = mysql_connect(DB_SERVER.":".DB_PORT,DB_USER,DB_PASSWORD);
// mysql_query("SET NAMES utf8");
mysql_set_charset('utf8');
mysql_select_db(DB_NAME, $db);
$sql1 = "SELECT * FROM `dtb_category` WHERE `category_id` = '$_GET[category_id]'";
$rs1 = mysql_query($sql1,$db);
$item1 = mysql_fetch_assoc($rs1);

MySQL 複数テーブルを結合して検索する

複数のテーブルを結合して、一つのテーブルのように見立てて、WHEREできる。

tb_menber
menber_id name birthday address

tb_profile
tall blood hobby

SELECT * FROM `tb_member` INNER JOIN `tb_profile`

すると
menber_id name birthday address tall blood hobby
に対して WHERE文が使える

phpで配列をソートする(数値の場合)

PHPのソート関数では数値が昇順降順にならないという話も多いが

第二引数に「SORT_NUMERIC」を入れるとうまく行く

arsort($point_id_array, SORT_NUMERIC);

arsort asort は値とキーの関係を保ったままソートされる

array(8) {
  [2]=>
  string(4) "80.2"
  [3]=>
  string(4) "78.3"
  [1]=>
  string(4) "77.1"
  [4]=>
  string(4) "25.4"
  [0]=>
  string(3) "6.0"
  [6]=>
  string(3) "2.6"
  [7]=>
  string(3) "0.7"
  [5]=>
  string(3) "0.5"
}

rsort sort は値とキーの関係を保たない

array(8) {
  [0]=>
  string(4) "80.2"
  [1]=>
  string(4) "78.3"
  [2]=>
  string(4) "77.1"
  [3]=>
  string(4) "25.4"
  [4]=>
  string(3) "6.0"
  [5]=>
  string(3) "2.6"
  [6]=>
  string(3) "0.7"
  [7]=>
  string(3) "0.5"
}

php で○時間前、○日前など

phpで相対的な日時を得る方法のメモ。昨日明日、先月来月、次の日曜前の日曜、3分前、10分後など、現在日時を起点にしたあらゆるパターンの日時が得られる。

strtotime()はUnixタイムスタンプを返す組み込み関数。日時の文字列を渡すとそれに応じたUNIXタイムスタンプを返してくれる。

  1. strtotime(“1999-12-31 23:59:59”);//946652399

で、strtotime()は日時以外に、様々な相対日時を指定可能になっている。strtotime( "yesterday" )とやると前日の午前0時0分0秒のUNIXタイムスタンプが返ってくる。これをdate()関数と組み合わせて使うことで、相対日時を簡単に取得することができる。

  1. date(“Y-m-d H:i:s”, strtotime(“yesterday”));//ex 2011-10-27 00:00:00

以下はstrtotime()で使える日時指定のリスト。

現在日時

  1. strtotime(“now”);

昨日明日、一昨日、明後日など前後の日付

  1. strtotime(“+1 day”);//明日
  2. strtotime(“+2 day”);//明後日
  3. strtotime(“+10 day”);//10日後
  4. strtotime(“+365 day”);//365日後
  5.  
  6. strtotime(“1 day”);//+は省いても構わない
  7.  
  8. strtotime(“-1 day”);//昨日
  9. strtotime(“-2 day”);//一昨日
  10. strtotime(“-10 day”);//10日前
  11. strtotime(“-365 day”);//365日前

昨日今日明日の0時0分0秒

  1. strtotime(“today”);//今日の0時0分0秒
  2. strtotime(“yesterday”);//昨日の0時0分0秒
  3. strtotime(“tomorrow”);//明日の0時0分0秒
  4.  
  5. strtotime(“yesterday 15:00:00”);//昨日の15時0分0秒

strtotime( "+1 day" )が現在時のちょうど24時間後になるのに対し、strtotime( "tomorrow" )だと明日の0時0分0秒が得られる。たまにstrtotime( "tomorrow" )strtotime( "+1 day" )は同じと書いているのを見かけるが間違い。異なった数値が返ってくるので使い分ける。 strtotime( "now" ) - strtotime( "today" )で今日が始まって何秒経過したとかできて便利。

正午

  1. strtotime("noon");//今日の12時0分0秒
  2.  
  3. strtotime("yesterday noon");//昨日正午

  1. strtotime("+1 week");//1週間後
  2. strtotime("+10 week");//10週後
  3. strtotime("-1 week");//1週間前
  4. strtotime("-10 week");//10週前

  1. strtotime("+1 month");//来月1日の0時0分0秒。
  2. strtotime("+2 month");//再来月1日の0時0分0秒。
  3. strtotime("-1 month");//先月1日の0時0分0秒。
  4. strtotime("-2 month");//2カ月前1日の0時0分0秒。
  5.  
  6. strtotime("2013-07");//2013年7月1日0時0分0秒。
  7. strtotime("january");//今日が28日だとすると、今年の1月28日の0時0分0秒。
  8.  
  9. strtotime("2013-08-01 +1 month");//2013年9月1日の0時0分0秒
  10. strtotime("2013-08-31 +1 month");//2013年10月1日の0時0分0秒になってしまう!
  11. strtotime("2013-08 +1 month");//2013年9月1日の0時0分0秒

日を指定せず、YYYY-MMを与えるとその月の1日になり、Januaryのように英語月名を与えると今日の日付になる。

+1 monthを使う時は、日付まで指定して使うと予想外の値になる場合がある。例えば、strtotime( "2013-08-31 +1 month" )とすると、返ってくる値は2013-09-30ではなく2013-10-01である。strtotime( "2013-08-30 +1 month" )なら2013-09-
30になる。どうやら+1 monthは、単純に月に1を足しているだけのもよう。つまり、2013-08-31という値を+1 monthすると、まず2013-09-31という文字列を作成し、次いでこれを2013-10-01に変換しているようなのだ。よって、月送りには日付を指定せずに使うのが良い。

月初・月末

  1. strtotime("first day of 2013-07-10");//2013年7月1日0時0分0秒。
  2. strtotime("
    first day of january"
    );//first dayは年を省き月だけの指定も可能。この場合は今年の1月1日0時0分0秒。
  3. strtotime("first day of 2013-07");//これでもOK
  4.  
  5. strtotime("last day of 2013-07-01");//2013年7月31日の0時0分0秒。
  6. strtotime("last day of january");//今年の1月31日0時0分0秒。
  7. strtotime("last day of 2013-07");//2013年7月31日の0時0分0秒。
  8.  
  9. strtotime("first day of next month");//来月1日0時0分0秒。

月末日は月によってバラバラなので、last day ofは非常に便利。「月」の項目でも説明したが、strtotime("2013-08-31 +1 month")は10月1日になってしまう。2013年8月の翌月の末日を得たい場合は、strtotime( "last day of 2013-08 +1 month" )とする。これで2013-09-30が得られる。

ただし、PHPのバージョンによっては(5.4.4以前?)、first day ofとlast day ofは動かない。確実に月初や月末を得たい場合はmktime()を使う方が良い。mktime()の第5引数を0にすると、前の月の末日が得られる。

  1. strtotime("+1 year");//現在日時の1年後. 今が2014年1月1日10時ちょうどなら返り値は'2015-01-01 10:00:00'
  2. strtotime("-1 year");//現在日時の1年前. 今が2014年1月1日10時ちょうどなら返り値は'2013-01-01 10:00:00'
  3.  
  4. strtotime("last year");// "-1 year"と同じ
  5. strtotime("next year");// "+1 year"と同じ
  6.  
  7. //特定の時刻が得たいなら以下の書き方が可能
  8. strtotime("+1 year 00:00:00");//現在日時の1年後の0時0分0秒になる01-01 10:00:00'

曜日

  1. strtotime("next sunday");//次の日曜の0時0分0秒
  2. strtotime("+2 sunday");//次の次の日曜0時0分0秒
  3. strtotime("last sunday");//前の日曜の0時0分0秒
  4. strtotime("-3 sunday");//3回前の日曜0時0分0秒
  5.  
  6. strtotime("next sun");//略称でもOK
  7.  
  8. strtotime("first sun of 2011-10"
    );//指定した月の最初の日曜の日付。時間は0時0分0秒
  9. strtotime("second sun of 2011-10");//指定した月の2つめの日曜の日付
  10. strtotime("last sun of 2011-10"));//指定した月の最後の日曜の日付
  11. strtotime("first sun of october 2011");//この書き方でもOK

時分秒

  1. strtotime("+5 sec");//5秒後
  2. strtotime("+5 min");//5分後
  3. strtotime("+1 hour");//1時間後
  4. strtotime("-5 sec");//5秒前
  5. strtotime("-5 min");//5分前
  6. strtotime("-1 hour");//1時間前
  7.  
  8. strtotime("+5 second");//秒はsec・secondどちらでも可
  9. strtotime("+5 minute");//分もmin・minuteどちらも可

組み合わせ

  1. strtotime("+1 month +1 day +1 hour +1 minute");//1カ月と1日と1時間1分後

$_Cookie の使い方

$time = time() + 70 * 24 * 3600; // 70日有効, 第3引数に過去時間をセットする事で削除可能
setcookie(“クッキー名”, “内容”, $time, “/”);

クッキーの保存数に制限があるので
クッキー名[0],クッキー名[1],クッキー名[2]… のように並列にすると一つのクッキーとして扱われる。

削除と更新、上書き
上書きはできないので一旦削除する
setcookie(“クッキー名”, “内容”, – $time, “/”); // 時刻を負の数として時間切れにすることで削除とみなされ、上書きできるようになる。

取り出すときは
$cookie = $_COOKIE[クッキー名];

AUTO_INCREMENTの値を更新する

AUTO_INCREMENTの値として代入する数値は「’」コロンで囲まない。

$sql = "ALTER TABLE `dtb_products_class_product_class_id_seq` AUTO_INCREMENT = 777";

ついでに
EC-CUBE のあるバージョンで発生した事例。

CSVによる商品登録のさい
dtb_products_class_product_class_id_seq や dtb_products_product_id_seq において
・AUTO_INCREMENT を更新する
・sequence を更新する
両方更新しないと管理画面からの商品登録でエラーになる。

phpMyadminにログインできない

 

ユーザー名やパスワードが間違っていない。
config.inc.php が間違っていない。
 

ログインがエラーにならないのに
ログイン画面に戻ってしまう。
ブラウザによっては「アクセスが拒否されました」と表示される。
 

つまり、パスワード云々ではなく、拒否される
権限が無いのね。
 

試しに
phpMyadmin/setup にアクセスしてみる。
↓こんなエラーだ
session_start(*************): open failed: Permission denied (13)
セッションが書き込めないのね、ということで
 

/var/lib/php/session のパーミッションを確認する

[root@hogehoge php]# ls -l
drwxrwx— 2 apache apache session

 

apache からの書き込みがOKでも動かない
動いているサーバーの設定を見てみると
webユーザーにも許可が出ている。
 

webユーザーも読み書きできるようにパーミッションを変えたら
phpMyadmin が無事に動きました。

EC-CUBEやWordpressは動いていたので、session_save_path を疑いませんでしたが
彼らは session_save_path を指定して権限を付与している。
phpMyadmin はデフォルトのsession_save_path を使っている。
session_save_path を指定して、権限を付与するのもOKってことですね。

データベースのメンテナンス

データベースのオーバーヘッドは、INSERT、DELETE、UPDATEを行っているうちにできるゴミ(未使用)領域のようなものです。

これを解消するためには、テーブルの最適化が必要です。

phpMyAdminからDB表示、画面一番下の「オーバーヘッドのあるテーブルを確認」→チェックが入る→ドロップダウンリストから「テーブルを最適化する」、で実行できます。

MySQLの条件ソートで大文字小文字が区別されない

WHEREで大文字小文字が区別されないなんて迷惑な機能があります。
大文字小文字を区別するには条件式の前に”INARY”を付加するといいらしい。

SELECT * FROM `dtb_coupon` WHERE BINARY `coupon_code` = ‘$_POST[use_coupon]’ AND `del_flg` = ‘0’

GDでサムネイルを生成する

まだ整理していません。下書きです。

// 画像フォルダ、※ 相対パス か DOCUMENT_ROOT で書く
$img_dir = '../img/upload/';
echo '
$img_dir=&gt;'.$img_dir;

$name = explode('.', $_GET[imgname]);

$tumbnail_name = $name[0].'_thumbnail.'.$name[1];

$img_path = $img_dir.$tumbnail_name;
echo '
$img_path=&gt;'.$img_path;

// 試験の場合は、前回生成の新画像を削除
// unlink($img_path);

if(!file_exists($img_path)){
echo '
Tumbnailが無いので自動生成します。';

// 注意
// 画像Pathは URLではなく Pathで書く。

// 元画像
$srcname = explode('_thumbnail', $img_path);
$srcname  = $srcname[0].$srcname[1];
echo '

$srcname=&gt;'.$srcname;

$image = ImageCreateFromJPEG($srcname);
echo '
$image=&gt;'.$image;
// 元画像のサイズを取得
$width = ImageSX($image);
$height = ImageSY($image);
echo '
$width=&gt;'.$width;
echo '
$height=&gt;'.$height;

// 縮小した画像のサイズを決める。
$new_width = 250;
$rate = $new_width / $width; //圧縮比
$new_height = $rate * $height;
echo '

$new_width=&gt;'.$new_width;
echo '
$new_height=&gt;'.$new_height;

// 空の画像を作成する。
$new_img = ImageCreateTrueColor($new_width, $new_height);

// 画像を普通にリサイズコピーする場合。
// ImageCopyResized($img_path,$image,0,0,0,0,$new_width,$new_height,$width,$height);
ImageCopyResized($new_img,$image,0,0,0,0,$new_width,$new_height,$width,$height);
// サンプリングしなおす場合。
// ImageCopyResampled($new_img,$image,0,0,0,0,$new_width,$new_height,$width,$height);

// ファイルに保存する場合。
ImageJPEG($new_img, $img_path, 100); //3つ目の引数はクオリティー(0~100)
// ImageGIF($image, $file_path);//環境によっては使えない
// ImagePNG($image, $file_path);
}
echo '<hr /><img src="'.$img_path.'" alt="" />';

※ PHP のGD関数はまだまだ途上のようです。随時使用が変わりますので、人の書いたものを信用せずに、公式サイトをご確認ください。

 

PHPで0サプレスする(数字の先頭から0を削除する)

《例》

$str = "000100";
echo $str;
//出力結果:000100

echo abs($str);
//出力結果:100

いろいろというか、もっと原始的なやり方を好むが、今回は便利な関数を使ってみた。
ベーシックな関数は必要だが、このような流行りもの的関数を使ってしまった自分が恥ずかしい。

画像サイズを取得してW:Hの最大値を調整する

画そうのサイズを取得する。
このとき画像のPathに注意が必要です。
SERVER_ROOT ではなく、DOCUMENT_ROOT で指定しましょう。

list($width, $height, $type, $attr) = getimagesize($_SERVER[DOCUMENT_ROOT]."/upload/save_image/".$item4[main_image].".jpg");
echo 'W:'.$width.' H:'.$height.'<br>';

画像の最大サイズを調整する。

$wid_max = '450';
$hei_max = '450';
if($width >= $height){
	if($width <= $wid_max){
		$html_size = ' width="'.$width.'"';
	}else{
		$html_size = ' width="'.$wid_max.'"';
	}
}else{
	if($height <= $hei_max){
		$html_size = ' height="'.$height.'"';
	}else{
		$html_size = ' height="'.$hti_max.'"';
	}
}

$img_html = '<img src="/upload/save_image/'.$item4&#91;comment6&#93;.'.jpg"'.$html_size.'>';
echo $img_html; 

クラスを配列に変える

stdClass などを個別に取り出すには、配列に変えたほうが便利なこともある。

一例です。

var_dump(aaa); の結果が下記のような場合

array(26) {
  [bbb]=>
  object(stdClass)#39 (18) {
    ["topic_id"]=>
    string(2) "74"
    ["topic_title"]=>
    string(5) "Title"
    ["topic_slug"]=>
    string(7) "title-4"
    ["topic_poster"]=>
    string(1) "3"
    ["topic_poster_name"]=>
    string(9) "hashimoto"
    ["topic_last_poster"]=>
    string(1) "3"
    ["topic_last_poster_name"]=>
    string(9) "hashimoto"
    ["topic_start_time"]=>
    string(19) "2011-06-03 10:46:03"
    ["topic_time"]=>

$vvv = (array)$aaa[bbb];

var_dump($vvv); とやると、配列になっている。

配列をランダムにシャッフルする

//---------------------------------------------
// ランダム化
//---------------------------------------------
// 乱数生成
function make_seed(){
	list($usec, $sec) = explode(' ', microtime());
	return (float) $sec + ((float) $usec * 100000);
}
srand(make_seed());
$randval = rand();
// シャッフル
shuffle($array);
$i = 0;
while($array[$i] != ''){
	echo $array[$i];
	$i ++;
}

季節で表示を変ええる

date関数で月日を4桁数字として取得する。
季節の月日と比較するだけ。

春  3月1日– 5月31日
夏  6月1日– 8月31日
秋  9月1日–11月31日
冬 12月1日–2月29日

&lt;?php
    // 今日の月日を取得
    $date = date(md);
    // 春
    if( ($date &gt;= 0310) && ($date &lt;= 0531) ){
        $tab_active = 'Spring';
    // 夏
    }elseif( ($date &gt;= 0601) && ($date &lt;= 0831) ){
        $tab_active = 'Summer';
    // 秋
    }elseif( ($date &gt;= 0901) && ($date &lt;= 1131) ){
        $tab_active = 'Autumn';
    // 冬
    }elseif( ($date &gt;= 1201) || ($date &lt;= 0229) ){
        $tab_active = 'Winter';
    }
?&gt;

AUTO_INCREMENTの値をリセットする方法

EC-CUBEなどで、カテゴリIDや商品IDを指定したいということもあるようです。
AUTO_INCREMENT(自動採番)を採用しているのは、指定する必要性が考えられないからです。
番号を指定したいというご要望も多いですね。
理由は聞かないことにしています。
辻褄の合う理由など存在しないのですから、聞いて腹だ立つのなら、聞かずに対応してしまいましょう。

操作は至って簡単!

ALTER TABLE &lt;テーブル名&gt; AUTO_INCREMENT = 1;

関連テーブルのIDの変更もお忘れなく…

phpでPDFを生成

FPDF 1.52 リファレンス マニュアル
http://www.ryuzee.com/manual/fpdf152ja/

FPDF日本語版 fpdf_ja

&lt;?php
require('mbfpdf.php');// 用紙サイズは、「縦・横」の配列で指定する
$size = array(182, 257);$pdf=new MBFPDF('P', 'mm', $size);
// $pdf = new MBFPDF('P', 'mm'. 'A4');

$pdf-&gt;AddMBFont(GOTHIC, 'EUC-JP');
$pdf-&gt;Open();
$pdf-&gt;AddPage();
$pdf-&gt;SetFont(GOTHIC, '', 8);
// $pdf-&gt;Cell(80, 16, "罫線付き背景色付き(中央寄せ)", 1, 1, "L", 0);
// $pdf-&gt;Cell(80, 16, "罫線付き背景色付き(中央寄せ)", 1, 1, "L", 0);
$pdf-&gt;Cell(80, 6, "伝票番号:000000", 0, 0, "L", 0);
$pdf-&gt;Cell(80, 6, "発行日 YYYY年 MM月 DD日", 0, 1, "R", 0);

$pdf-&gt;SetFont(GOTHIC, '', 13);
$pdf-&gt;Cell(160, 16, "納品書兼販売証明書", 1, 1, "C", 0);

// space
$pdf-&gt;Cell(80, 20, " ", 0, 1, "L", 0);

$pdf-&gt;SetFont(GOTHIC, '', 10);
$pdf-&gt;Cell(80, 8, "エンドユーザー様 ", 0, 0, "L", 0);
$pdf-&gt;Cell(80, 8, "会員様会社名 店舗名", 0, 1, "L", 0);

$pdf-&gt;SetFont(GOTHIC, '', 8);
$pdf-&gt;Cell(80, 6, "〒000-0000 ", 0, 0, "L", 0);
$pdf-&gt;Cell(80, 6, "〒111-1111", 0, 1, "L", 0);

$pdf-&gt;Cell(80, 6, "○○県△△市☆町7-77", 0, 0, "L", 0);
$pdf-&gt;Cell(80, 6, "茨城県つくば市千現1-14", 0, 1, "L", 0);

$pdf-&gt;Cell(80, 6, "○○ビル2F", 0, 0, "L", 0);
$pdf-&gt;Cell(80, 6, "△△マンション707", 0, 1, "L", 0);

$pdf-&gt;Cell(80, 6, "TEL:000-0000-0000", 0, 0, "L", 0);
$pdf-&gt;Cell(80, 6, "TEL:111-1111-1111", 0, 1, "L", 0);

// space
$pdf-&gt;Cell(80, 20, " ", 0, 1, "L", 0);

$pdf-&gt;Cell(160, 10, "この度はお買い上げ頂まして誠にありがとうございます。", 0, 1, "L", 0);

$pdf-&gt;Cell(160, 10, "ご注文番号:1234567", 0, 1, "L", 0);

$pdf-&gt;SetFillColor(200, 200, 200); //背景色
$pdf-&gt;Cell(40, 6, "品番", 1, 0, "C", 1);
$pdf-&gt;Cell(100, 6, "商品名", 1, 0, "C", 1);
$pdf-&gt;Cell(20, 6, "数量", 1, 1, "C", 1);

$pdf-&gt;Cell(40, 6, "N000111", 1, 0, "C", 0);
$pdf-&gt;Cell(100, 6, "商品名商品名商品名", 1, 0, "C", 0);
$pdf-&gt;Cell(20, 6, "1", 1, 1, "C", 0);

$pdf-&gt;Cell(160, 40, "修理等のご依頼の際には、この販売証明書が必要となりますので大切に保管してください。", 0, 1, "L", 0);

$pdf-&gt;Output();

?&gt;

このようなファイルを作ればOKだが、このファイルのエンコードはEUCにしないと文字化けになる。
shisで化けないのが正解のような気がするが、そのうちに究明しよう!

フィールド名とフォーム名の自動化

フィールド名を勝手に抽出し、
POSTがあれば、POSTを優先
無ければDBを優先
これを勝手に行うソースコード

この記事に出会ったあなたはラッキーです。

// テーブル抽出(1レコードのみ)
$sql = "SELECT * FROM `TABLE_NAME` LIMIT 1";
$statement = $pdo->query($sql);
$item = $statement->fetch(PDO::FETCH_ASSOC);

// Key を配列化
$key_arr = array();
foreach($item as $key => $val){
    // echo $key."=>".$val."&lt;br&gt;"; // 試験表示
    array_push($key_arr, $key);
}

// POST があれば変数に代入、無ければテーブルから変数に代入
$i="0";
while($key_arr[$i]!=""){
    $value=$key_arr[$i];
    
    // POST があれば変数に代入
    if(($_POST[$value]!="") && ($_POST[$value]!="NULL")){
        $$value=$_POST[$value];
    
    // 無ければテーブルから変数に代入
    }else{
        $$value=$item[$value];
    }
    
    $i ++;
}

ECCUBEの文字化け

サーバ移転や、試験環境などの構築で、文字化けが発生することがしばしばある。
データベース接続まわりを除いてみると、大切な記述が欠けている。

ファイル名: /data/class/SC_DbConn.php
65行付近

$this->conn = $objDbConn;
$this->conn->query("SET NAMES utf8");
$this->error_mail_to = DB_ERROR_MAIL_TO;
$this->error_mail_title = DB_ERROR_MAIL_SUBJECT;
$this->err_disp = $err_disp;
$this->dbFactory = SC_DB_DBFactory_Ex::getInstance();
$this->conn->query("SET NAMES utf8");

を追記すれば解決する。

※ この作業を行うタイミングが重要です。
インストールのどのタイミングで行うか、DB接続直後です。

注意
エンコード関連を変更した後は、キャッシュファイルのクリアを忘れるべからず。

解説
php.ini のエンコード関係は、あまり指定しないのがサーバー屋の流儀である。
その場合、データベースの読み書きは、サーバーのデフォルト・エンコードで行われる。

サーバーのエンコードは、
最近は、UTF-8が多くなってきたが、以前はEUCが主流だった。

DBのエンコードとPHPファイルのエンコードが同じであっても、文字化けが発生する場合は、サーバーのデフォルトエンコードを疑うのが基本である。

GDでサムネイル生成

&lt;?php

$dir  = 'test/';     //画像格納フォルダ
$file = 'test.png';  //画像ファイル名
$max  = 200;         //サムネイルのサイズ

if (preg_match('/\.gif$/i', $file)) {
    $image = imagecreatefromgif($dir . $file);
} elseif (preg_match('/\.(jpeg|jpg|jpe)$/i', $file)) {
    $image = imagecreatefromjpeg($dir . $file);
} elseif (preg_match('/\.png$/i', $file)) {
    $image = imagecreatefrompng($dir . $file);
}

$width  = imagesx($image);
$height = imagesy($image);

if ($width > $height) {
    if ($width > $max) {
    $new_width  = $max;
    $new_height = ($new_width / $width) * $height;
    } else {
    $new_width  = $width;
    $new_height = $height;
    }
} else {
    if ($height > $max) {
    $new_height = $max;
    $new_width  = ($new_height / $height) * $width;
    } else {
    $new_width  = $width;
    $new_height = $height;
    }
}

$new_image = imagecreatetruecolor($new_width, $new_height);

imagecopyresized($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);      //アンチエイリアスなし
//imagecopyresampled($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);  //アンチエイリアスあり

if (preg_match('/\.gif$/i', $file)) {
    imagegif($new_image, $dir . 'copy_of_' . $file);
} elseif (preg_match('/\.(jpeg|jpg|jpe)$/i', $file)) {
    imagejpeg($new_image, $dir . 'copy_of_' . $file, 70);
} elseif (preg_match('/\.png$/i', $file)) {
    imagepng($new_image, $dir . 'copy_of_' . $file);
}

imagedestroy($image);
imagedestroy($new_image);

?&gt;

[/php]

Perl で Mysql

ひとつはPPMにCPANを登録する事。
メニューの「Edit」→「Reference」→「Repositories」にて「Name」は適当に、「Location」に「http://cpan.uwinnipeg.ca/PPMPackages/10xx/」と入力して「Add」ボタンをクリックして登録。
これでCPANに接続しする事ができ、CPANからもモジュールをダウンロードする事ができる。

ふたつ目はコマンドプロンプトから「perl -MCPAN -e shell」と入力。
これはCPANとコマンドで対話する事ができるシェルコマンド。
「cpan>」の後に「install DBD::mysql」と入力してモジュールをダウンロード&インストールするのだ。

レコードの検索

////////////////
// 比較演算子 //
////////////////

where フィールド名 = ‘値’ レコードが値と等しい場合
where フィールド名 <> ‘値’ レコードが値と等しくない場合
where フィールド名 > ‘値’ レコードが値よりも大きい場合
where フィールド名 >= ‘値’ レコードが値以上である場合
where フィールド名 < '値' レコードが値より小さい場合 where フィールド名 <= '値' レコードが値以下である場合 //////////////////// // その他の演算子 // //////////////////// where フィールド名 between '値1' and '値2' レコードが値1と値2の間である場合値1と値2も含む where フィールド名 in ('値1', '値2'...) レコードがいずれかの値である場合複数の値を指定できる where フィールド名 is null レコードがnull値である場合 where フィールド名 is not null レコードがnull値でない場合 where フィールド名 like '値%' 値から始まるレコードを検索前方一致 where フィールド名 like '%値%' 値を含むレコードを検索中間一致 where フィールド名 like '%値' 値で終わるレコードを検索後方一致 //////////////// // 論理演算子 // //////////////// where 条件1 and 条件2 条件1でありかつまた条件2である場合(論理積) where 条件1 or 条件2 条件1あるいは条件2である場合(論理和) where not (条件) 条件でない場合(論理否定)

郵便番号を住所変換する

DBは郵便サイトからダウンロード
http://www.post.japanpost.jp/zipcode/dl/kogaki.html

SQL文(1)
テーブル生成

CREATE TABLE mtb_zipcode (
jis varchar(10) NULL,
zip_old varchar(5) NULL,
zip varchar(7) NULL,
addr1_kana varchar(100) NULL,
addr2_kana varchar(100) NULL,
addr3_kana varchar(100) NULL,
addr1 varchar(100) NULL,
addr2 varchar(100) NULL,
addr3 varchar(100) NULL,
c1 int NULL,
c2 int NULL,
c3 int NULL,
c4 int NULL,
c5 int NULL,
c6 int NULL
)

SQL文(2)
データ挿入
vscファイルのエンコードを調整しておく

LOAD DATA LOCAL INFILE '/home/_DATABASE_BACKUP/KEN_ALL_UTF8.csv'
INTO TABLE `tb_zip_code`
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'

文字を画像化する(Imagemagick)

当然のことですが、日本語を利用する場合、日本語対応フォントを利用します。

$text="あいうえおかきくけこ";
$org_fname="`元ファイル名";
$new_fname="新ファイル名";
$fontsize="30";
$x="40";
$y="270";
$color="white";

// 必要ならエンコード
//$text = mb_convert_encoding($text, 'UTF-8','auto');

$cmd = "convert -fill ".$color." -font kochi-gothic-subst.ttf -pointsize ".$fontsize." -annotate +".$x."+".$y." ".$text." img/".$org_fname." img/".$new_fname;

exec($cmd);

※ 元画像の指定位置に文字画像をのせます。

PHP でモンタージュ作成

Imagemagick の montage関数 を利用します。

複数の画像から複数画像のサムネイルを一つの画像として作成する。
$cmd=”montage -geometry 40×40+5+5 -tile 3×3 -background #ffffff -bordercolor #BBBBBB -border 2 -quality 75 ./ディレクトリ/*.jpg ./ディレクトリ/新ファイル名;

exec($cmd);

さらにトリミングする場合
$cmd=’montage -tile 2×3 -resize 160x -resize “x250<" -resize 50%% -gravity center -crop 105x105+0+0 -geometry 105x105+1+1 -background "#000000" -bordercolor "#BBBBBB" -border 0 -quality 100 ./ディレクトリ/*.jpg ./ディレクトリ/新ファイル名; exec($cmd); 解説 -resize 高さが指定値を超えているもののみ『比率を保持したまま高さを指定値』へ縮小する -resize 50%%で半分の大きさに縮小する -gravity centerで画像を中央に寄せる -crop 70x70+0+0で中央部分を切り抜き -geometry 70x70+10+10で70x70の土台にのせる