4 byte character checking for PHP

Some of the pictograms and Chinese characters are 4bytes of UTF-8 characters, and cannot be saved depending on the version of mysql and character code. I think there is something I want to check that there are more characters than the UTF-8 range in the string.

let’s look at sample, cherry blossom is 4 byte characters.

mb_internal_encoding('UTF-8');
$char = 'abcdefgあいうえお🌸';

echo preg_replace('/[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF]/', '', $char);

abcdefgあいうえお
Wow, it’s impressive.

Ok then, I want to display an alert if 4-byte characters are included.
Let’s see regular expression below.

mb_internal_encoding('UTF-8');
$char = 'abcdefgあいうえお';
// $char = 'abcdefgあいうえお🌸';

// echo preg_replace('/[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF]/', '', $char);

if(preg_match('/[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF]/', $char)){
	echo "alert, it included 4 byte";
} else {
	echo "there is no 4 byte charcter";
}

Oh my goodness.
“just trust yourself. surely, the way to live is coming. Goethe”

String Byte conversion for PHP

Let’s look up hex2bin function in php manual.
hex2bin

It says “Decodes hexadecimally encoded binary string”.

Example 1

mb_internal_encoding('UTF-8');
$char = 'あ';

echo bin2hex($char);

result: e38182

This is the unicode standard manual
Unicode.org
UTF8 has 1byte to 4 byte characters.

What happen about in the case of Emoji?
🌸 Cherry blossom: 1F338

mb_internal_encoding('UTF-8');
$char = '🌸';

echo bin2hex($char);

f09f8cb8
A number different from unicode was displayed.
Comversion seems to be done without problems.

S3へのアップロード

if(file_exists($_FILES['upfile']['tmp_name'])){
	$ext = substr($_FILES['upfile']['name'], strrpos($_FILES['upfile']['name'],'.') + 1);
	echo $ext."<br>";
	if(strtolower($ext) !== 'png' && strtolower($ext) !== 'jpg' && strtolower($ext) !== 'jpeg' && strtolower($ext) !== 'gif'){
		echo '画像以外のファイルが指定されています。画像ファイル(png/jpg/jpeg/gif)を指定して下さい';
		exit();
	}

	$tmpname = str_replace('/tmp/', '', $_FILES['upfile']['tmp_name']);
	echo $tmpname;
	// $new_filename = 'profiles/'.$id.'-'.time().'-'.$tmpname.'.'.$ext;



$s3clinet = S3Client::factory([
		'credentials' => [
		'key' => env('AWS_ACCESS_KEY_ID'),
		'secret' => env('AWS_SECRET_ACCESS_KEY'),
		],
		'region' => 'northeast-1',
		'version' => 'latest',
]);

$bucket = getenv('zeus-image')?: die('no zeus-image config var in found in env!');

$image = fopen($_FILES['upfile']['tmp_name'],'rb');

// 画像アップロード
$result = $s3client->putObject([
		'ACL' => 'public-read',
		'Bucket' => $bucket,
		'Key' => $new_filename,
		'Body' => $image,
		'ContentType' => mime_content_type($_FILES['upfile']['tmp_name']),
]);

}

これでいいのか?いや、良くない、アップロードされてない。。
require ‘vendor/autoload.php’;を足せばよい?? なんかちゃうなー。。

php fopenの’rb’とは?

tmpファイルのアップロードで、以下の様に書いていた。

$image = fopen($_FILES['upfile']['tmp_name'],'rb');

ところで、この’rb’って何? 一瞬、rubyの拡張子に見えたんだが、絶対違うよな。。
‘b’は強制的にバイナリモードにします。
fopen(‘file’,’r’): 読み込みのみで開く。ファイルポインタはファイルの先頭におく。
fopen(‘file’,’r+’): 読み書き可能な状態で開く。ファイルポインタはファイルの先頭におく。
‘b’は強制的にバイナリモードにする。

よって fopen(‘file’,’r’); は、読み込みのみで開く。強制的にバイナリモードにする。

バイナリモードで開くってことね♪

phpでアップロードした画像のファイル名を取得しよう

まずformでアップロード機能をサクッと作ります。

<?php
if(file_exists($_FILES&#91;'upfile'&#93;&#91;'tmp_name'&#93;)){
	$ext = substr($_FILES&#91;'upfile'&#93;&#91;'name'&#93;, strrpos($_FILES&#91;'upfile'&#93;&#91;'name'&#93;,'.') + 1);
	echo $ext."<br>";
	if(strtolower($ext) !== 'png' && strtolower($ext) !== 'jpg' && strtolower($ext) !== 'jpeg' && strtolower($ext) !== 'gif'){
		echo '画像以外のファイルが指定されています。画像ファイル(png/jpg/jpeg/gif)を指定して下さい';
		exit();
	}

	$tmpname = str_replace('/tmp/', '', $_FILES['upfile']['tmp_name']);
	echo $tmpname;
	// $new_filename = 'profiles/'.$id.'-'.time().'-'.$tmpname.'.'.$ext;
}

?>
<div id="content">
<h2>画像管理</h2>
<hr>
<form action="#" method="POST" enctype="multipart/form-data">
<div id="drag-drop-area">
 <div class="drag-drop-inside">
  <p class="drag-drop-info">ここにファイルをアップロード</p>
  <p>または</p>
  <!-- <input type="file" value="ファイルを選択" name="image"> -->
  <p class="drag-drop-buttons"><input id="fileInput" type="file" value="ファイルを選択" name="upfile"></p>
      <input type="submit" value="送信">
   </div>
  </div>
</form>

アップロード前

アップロード後

うん、上手くいってるようです。
さて、s3をやりましょう。ここまで長かった。

phpのstrtolowerとは?

strtolower — 文字列を小文字にする

読んで字の如く、という感じですね。
サンプル

echo strtolower("Jpeg");

jpeg

想定通りです。裏側のアルゴリズムを想像すると、ワクワクしますね。
jsやjava、pythonなどでもあるようです。

phpのstrrposで日本語を扱う時

strrpos: 文字列の中に、ある部分の文字列が最後に現れる場所を探す
int strrpos(string $haystack, string $needle)

echo strrpos("あいうえお", "う");

6?
あれ?どういうことだ?

echo strrpos("phpengineer", "h");

1

あれ、半角英数字だと上手くいく。日本語だと駄目なのか?

echo strrpos("日本語で試します", "で");

9

あ、わかった、これはバイト数でカウントしてるんだな。
日本語は一文字3バイトだから、012, 345, 678, 9
で、9ということだろう。

試しに4バイトの漢字を入れてみましょう。
「𡈽」を使ってみます。
参考: UTF-8で4バイトになる文字 https://www.softel.co.jp/blogs/tech/archives/596

echo strrpos("𡈽は4バイトです", "は");

4
あ、やっぱりそうですね。
なるほどー

composerでaws/aws-sdk-phpインストール時にエラー

aws-sdk-phpを入れようとします。

composer.json

"require": {
    "aws/aws-sdk-php": "3.*",
}
[vagrant@localhost app]$ php composer.phar install aws/aws-sdk-php


  [Seld\JsonLint\ParsingException]
  "./composer.json" does not contain valid JSON
  Parse error on line 1:
    "aws/aws-sd
  --------^
  Expected one of: 'EOF', '}', ',', ']'

あれ? JSONが違う

{
	"require": {
    "aws/aws-sdk-php": "3.*"
	}
}

再度インストールします。上手くいきそうです。

[vagrant@localhost app]$ php composer.phar install
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 7 installs, 0 updates, 0 removals
– Installing mtdowling/jmespath.php (2.4.0): Loading from cache
– Installing ralouphie/getallheaders (2.0.5): Downloading (100%)
– Installing psr/http-message (1.0.1): Loading from cache
– Installing guzzlehttp/psr7 (1.5.2): Downloading (100%)
– Installing guzzlehttp/promises (v1.3.1): Loading from cache
– Installing guzzlehttp/guzzle (6.3.3): Loading from cache
– Installing aws/aws-sdk-php (3.82.6): Downloading (100%)
guzzlehttp/guzzle suggests installing psr/log (Required for using the Log middleware)
aws/aws-sdk-php suggests installing doctrine/cache (To use the DoctrineCacheAdapter)
aws/aws-sdk-php suggests installing aws/aws-php-sns-message-validator (To validate incoming SNS notifications)
Writing lock file
Generating autoload files

phpで文頭半角ドット(.)を正規表現(preg_match)

まず文章を用意します。
test.txt

.Linuxは無料です。あなたの時間に価値が無いなら。
Jamie Zawinski

1行ずつ正規表現でみていき、文頭に半角ドットがあった場合は、エラーをアラートメッセージを出します。

ini_set('mbstring.internal_encoding' , 'UTF-8');
$file = fopen("test.txt", "r");

if($file){
	while($line = fgets($file)){
		if(preg_match('/^./', $line)){
			echo "文頭に半角ドットが含まれています". "<br>";
		} else {
			echo $line . "<br>";
		}	
	}
}

fclose($file);

なに!? 半角ドットがエスケープされていない。

if($file){
	while($line = fgets($file)){
		if(preg_match('/^\./', $line)){
			echo "文頭に半角ドットが含まれています". "<br>";
		} else {
			echo $line . "<br>";
		}	
	}
}

出来たー