[PHP8.0.3] Fine-Diffによる差分解析

PHP Fine-Diffを使います。
GitHub:PHP-FineDiff

$ git clone https://github.com/gorhill/PHP-FineDiff.git

include 'finediff.php';

$filename1 = 'sample_from.txt';
$from_text = file_get_contents($filename1);

$filename2 = 'sample_to.txt';
$to_text = file_get_contents($filename2);

$opcodes = FineDiff::getDiffOpcodes($from_text, $to_text);

var_dump($opcodes);

$ php index.php
string(534) “c64di:9cd2i2:58c3di:9cdi4:Febrcd4i3:aryc4di:1c17di:uc185i:,c6dc84di:uc120d2i: c122di:uc238di:uc113di:uc528di:bc325di:uc106di:uc36di:uc185di:uc371di:uc267di:uc92di:uc124dc8dc5di:
c335di:uc78di:uc11di3:immcdi4:nselc39di:.ci31:The region visible from Earth (c15d4i4:univc2i3:se)c4d12c4d2i3:herc2i5:with ci15: radius of abouc2d5i2:46cd3c19d8i:,c5i83:based on where the expansion of space has taken the most distant objects observed. c763i:1cdc10d31c36di2:30c14d4i2:3?c3di:3ci:.c4dc474di:uc172di:uc191di:uc166di:uc435di:uc66d34c29di:uc1039”

🤔、ちょっとよくわからんな。

[CentOS8] PHP8インストールしよう

$ cat /etc/redhat-release
CentOS Linux release 8.2.2004 (Core)
$ php -v
-bash: php: command not found
$ sudo yum update

$ sudo yum install epel-release
$ sudo yum update epel-release
$ sudo rpm -ivh http://rpms.remirepo.net/enterprise/remi-release-8.rpm
$ sudo rpm –import http://rpms.remirepo.net/RPM-GPG-KEY-remi

$ export LC_ALL=C
$ printenv | grep LC
$ sudo yum config-manager –set-enabled remi

$ sudo yum module reset php
$ sudo yum module install php:remi-8.0

$ sudo yum install php php-devel php-pdo php-mysqlnd php-mbstring php-gd

$ php -v
PHP 8.0.3 (cli) (built: Mar 2 2021 16:37:06) ( NTS gcc x86_64 )

ヒョエエええええええ

RabbitMQの送受信

送信側
send.php

require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

// コネクションの確立
$connection = new AMQPStreamConnection('192.168.33.10', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->queue_declare('hello', false, false, false, false);

$msg = new AMQPMessage('Whats up');

$channel->basic_publish($msg, '', 'hello');

echo "[x] sent 'Hello World!'\n";

$channel->close();

受信側

require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;

$connection = new AMQPStreamConnection('192.168.33.10', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->queue_declare('hello', false, false, false, false);

echo "[*] Waiting for messages. To exit press CTR+C\n";

$callback = function($msg){
	echo '[x] Received ', $msg->body, "\n";
};

$channel->basic_consume('hello', '', false, true, false, false, $callback);

while(count($channel->callbacks)){
	$channel->wait();
}

$ php recieve.php
PHP Fatal error: Uncaught PhpAmqpLib\Exception\AMQPIOException: stream_socket_client(): unable to connect to tcp://192.168.33.10:5672 (Connection refused) in /home/vagrant/dev/mailer/vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/IO/StreamIO.php:111

サーバにRabbitMQをインストールしないとダメなのか。。

[PHP7.4.11] 再度composerを理解する

$ mkdir my-package
$ cd my-package
$ composer init
This command will guide you through creating your composer.json config.

Package name (/) [vagrant/my-package]: hpscript/my-package
Description []:
Author [hpscript <>, n to skip]:
Minimum Stability []: stable
Package Type (e.g. library, project, metapackage, composer-plugin) []: library
License []: MIT

composer.json

{
    "name": "hpscript/my-package",
    "type": "library",
    "license": "MIT",
    "minimum-stability": "stable",
    "require": {}
}

$ composer require vlucas/phpdotenv
$ composer require monolog/monolog
$ composer require phpunit/phpunit –dev
$ composer require psy/psysh:@stable –dev
-> dotenvとは、getenv()メソッドや、$_ENV変数、$_SERVER変数を使って、.envというファイルから環境変数を読み込む
-> REPLは対話型評価環境

### ディレクトリの作成
$ mkdir -p src/MyPackage/Exception
$ mkdir logs
$ mkdir tests
$ mkdir docs
$ mkdir example
$ mkdir bin

PSR-4: PHPでのファイルの読み込み・クラスのオートロードを行う仕様
composer.json

    "autoload": {
        "psr-4": {
            "hpscript\\MyPackage\\": "src/MyPackage/"
        }
    }

$ composer dump-autoload
Generating autoload files
Generated autoload files

.env

TEST_NAME=hpscript

.gitignore

/vendor
.env

logs/.gitignore

*
!.gitignore

psysh.php

#!/usr/bin/env php
<?php
// 名前空間
namespace hpscript\MyPackage;

require_once __DIR__ . '/vendor/autoload.php';

$dotenv = new \Dotenv\Dotenv(__DIR__.'/');
$dotenv->load();

echo __NAMESPACE__ . " shell\n";

$sh = new \Psy\Shell();

$sh->addCode(sprintf("namespace %s;", __NAMESPACE__));

$sh->run();

echo "Bye.\n";

$ chmod +x psysh.php

phpunit.xml

<?xml version="1.0" encoding="utf-8" ?>
<phpunit colors="true" bootstrap="vendor/autoload.php">
	<testsuites>
		<testsuite name="All tests">
			<directory>tests/</directory>
		</testsuite>
	</testsuites>
</phpunit>

monolog

namespace hpscript\MyPackage;

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;

class LogSample{

	public static function write($message){
		$log = new Logger("my-package");
		$log_path = __DIR__. '/../../logs/test.log';
		$handler = new StreamHandler($log_path,Logger::DEBUG);
		$log->pushHandler($handler);
		$rotating_handler = new RotatingFileHandler($log_path, 30, Logger::DEBUG, true);
		$log->pushHandler($rotating_handler);

		return $log->addDebug($message);
	}
}

### phpunit
src/MyPackage/Arithmetic.php

namespace hpscript\MyPackage;

class Arithmetic {
	public function add($x, $y){
		return($x + $y);
	}

	public function subtract($x, $y){
		return($x - $y);
	}

	public function multiply($x, $y){
		return($x * $y);
	}

	public function divide($x, $y){
		return($x / $y);
	}
}

tests/ArithmeticTest.php

use PHPUnit\Framework\TestCase;
use hpscript\MyPackage\Arithmetic;

class ArithmeticTest extends TestCase {

	protected $object;

	protected function setUp(): void{
		$this->object = new Arithmetic();
	}

	public function add5(){
		$this->assertEquals(8, $this->object->add(3, 5));
	}

	public function add30(){
		$this->assertEquals(45, $this->object->add(15, 30));
	}

	public function subtract3(){
		$this->assertEquals(7, $this->object->subtract(10, 3));
	}

	public function subtract9(){
		$this->assertEquals(-6, $this->object->subtract(3, 9));
	}

	public function multiply6(){
		$this->assertEquals(24, $this->object->multiply(4, 6));
	}

	public function multiply5(){
		$this->assertEquals(-20, $this->object->multiply(4, -5));
	}

	public function testDivide(){
		$this->assertEquals(3, $this->object->divide(6, 2));
		$this->assertEquals(1, $this->object->divide(6, 6));

$ ./vendor/bin/phpunit
PHPUnit 9.5.2 by Sebastian Bergmann and contributors.

. 1 / 1 (100%)

Time: 00:00.002, Memory: 6.00 MB

OK (1 test, 2 assertions)

$ php psysh.php
hpscript\MyPackage shell
Psy Shell v0.10.6 (PHP 7.4.11 — cli) by Justin Hileman
>>> $ar = new Arithmetic()
=> hpscript\MyPackage\Arithmetic {#2562}
>>> show $ar
5: class Arithmetic {
6: public function add($x, $y){
7: return($x + $y);
8: }
9:
10: public function subtract($x, $y){
11: return($x – $y);
12: }
13:
14: public function multiply($x, $y){
15: return($x * $y);
16: }
17:
18: public function divide($x, $y){
19: return($x / $y);
20: }
21: }

>>> ls $ar
Class Methods: add, divide, multiply, subtract
>>> q
Exit: Goodbye
Bye.

おお、なんか完璧には理解してないが、大まかな流れはわかった。

[PHP7.4.11] Composerの仕組み

ComposerとはPHPのパッケージ管理システム。
ライブラリをzip等でダウンロードせずに利用できる。

$ php -v
PHP 7.4.11 (cli) (built: Oct 21 2020 19:12:26) ( NTS )
$ composer
______
/ ____/___ ____ ___ ____ ____ ________ _____
/ / / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__ ) __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
/_/
Composer version 2.0.4 2020-10-30 22:39:11

composer.json

{
	"require": {
		"ircmaxell/random-lib": "1.0.0"
	}
}

$ composer install

require_once "vendor/autoload.php";

$factory = new RandomLib\Factory;
$generator = $factory->getMediumStrengthGenerator();

$randomInt = $generator->generateInt(5, 15);
echo $randomInt;

echo "\n";

$randomString = $generator->generateString(32, 'abcdef');
echo $randomString;

$ php app.php
12
cffccdccbcaadcffbbddbffbdadbfefd

requrire_onceした後にclassを作って読み込めば良いのね

/vendor/ircmaxell/random-lib/lib/RandomLib/Factory.php


public function getGenerator(\SecurityLib\Strength $strength) {
        $sources    = $this->getSources();
        $newSources = array();
        foreach ($sources as $source) {
            if ($strength->compare($source::getStrength()) <= 0) {
                $newSources[] = new $source;
            }
        }
        $mixer = $this->findMixer($strength);
        return new Generator($newSources, $mixer);
    }

    // 省略

    public function getMediumStrengthGenerator() {
        return $this->getGenerator(new Strength(Strength::MEDIUM));
    }

generateIntのclassも同様に、RandomLib/Generator.phpで書かれていますね。
なるほど。

[PHP7.4.16] CSVからKeyとValueの連想配列を作る

まず、CSVにデータがある

このデータを元に連想配列を作る

$data = [];
$fp = fopen("Book.csv", "r");
while(! feof($fp)){
	$csv = fgets($fp);
	$csv = trim($csv,'"');
	$csv = mb_convert_encoding($csv, "UTF-8", "utf-8");
	$csv = str_replace('"','',$csv);
	$array = explode(",",$csv);
	$data[$array[0]] = $array[1];
}

echo "<pre>";
var_dump($data);
echo "</pre>";

まあOKっぽい。。

[PHP7.4.11] 配列の先頭から複数の値を取り出す

$animals = ["cat", "dog", "tiger","rabbit"];
$animals = array_slice($animals, 1, 3);

var_dump($animals);

array(3) { [0]=> string(3) “dog” [1]=> string(5) “tiger” [2]=> string(6) “rabbit” }

例えば、値が2つしかなくて、3つ取り出そうとしたら、

$animals = ["cat", "dog"];
$animals = array_slice($animals, 0, 3);

var_dump($animals);

array(2) { [0]=> string(3) “cat” [1]=> string(3) “dog” }

値がないときはnullとなる。
OK!

[PHP 7.4.11] CSVパスワードリストをハッシュ化したパスワードリストに変換

csvでパスワードリストを読み取り、1行ずつハッシュ化したパスワードに変えて、新しいハッシュ化リストcsvを作る。
ハッシュ化はpassword_hash($value, PASSWORD_DEFAULT);で書く。

if (($handle = fopen("list.csv", "r")) !== FALSE) {
    while (($data = fgetcsv($handle))) {
        foreach ($data as $value) {
        	$hashedpassword = password_hash($value, PASSWORD_DEFAULT);
            $list[] = array($value, $hashedpassword);
        }
    }
    fclose($handle);
}

$fp = fopen('new_list.csv', 'w');
foreach ($list as $fields) {
    fputcsv($fp, $fields);
}
fclose($fp);

echo "done";

password1,$2y$10$9Bonz2Ou5aJ1eOJl8Nf9eOipsRRWLpPbesCn.05J.W/pu0vItQ2mW
password2,$2y$10$d4OP/5HRbNWnS2BJS7w4puvWWXCj4Y2dxAmp0wS2E84Mpvc2udCqK
password3,$2y$10$u7IghXiVsUsVarK.n46X3eqP/uAzYMmtPCXLynXtYYy5nUlSCC0b6
password4,$2y$10$qgaJzGVySJT6ll7k3I0ZwewX/ia.a2KVK3XLjH/VJuSXJ4nzdi4Fy
password5,$2y$10$VcejFdWMC6M/hI4BRZfyyeglttkqzbO41TZUexek6b58rxejgYcKG
password6,$2y$10$.lhQys3h4ukEGxn8azvzDu76l0KHNvjZYxAHfPcLu3zvshbHV78oC
password7,$2y$10$KVWoquH7WRj1bDn2l88vo.N845A4vwvuguMxRPX1G/m6uF9q63A5C
password8,$2y$10$PFDr/P4fpC0kmxQofbfb0.jHGDvQqJoRe8RPCyQlYkDozCLWhjCLy
password9,$2y$10$ZAvichguRHYMkc42fPVXVex8x7xp9/by/BDmOVaW6vRpvMSr7dIm6
password10,$2y$10$L09R/P2BX2ougk3rxHVqWelI/rJrFlTlkVr4RE7U/chw7tWZob1gu

$list[] = array($value, $hashedpassword); のところで、$hashedpasswordだけの配列を作るときは、$list[] = $hashedpasswordではなく、$list[] = array($hashedpassword);とする。

Ok, Not bad, keep going

[PHP 7.4.11] 連想配列で値を扱う

普通の連想配列です。

$sales =
	[
		"a" => 200,
		"b" => 300,
		"c" => 400
	];

var_dump($sales);

array(3) { [“a”]=> int(200) [“b”]=> int(300) [“c”]=> int(400) }

$key と $valueがあり、連想配列の中に$keyがなければ追加していく。
arsortで降順でソートする。

$key = "d";
$value = 250;

$sales =
	[
		"a" => 200,
		"b" => 300,
		"c" => 400
	];

if($sales[$key] !== null){
	$sales[$key] += $value;
} else {
	$sales += array($key => $value);
}

arsort($sales);
var_dump($sales);

array(4) { [“c”]=> int(400) [“b”]=> int(300) [“d”]=> int(250) [“a”]=> int(200) }

なんかOKっぽいな。多分。

[PHP 7.4.11] 先頭からの0取り処理(0埋め処理の逆)

0埋め処理(sprintf)とは逆に、文字列先頭からの0取り処理を実装したい。

### intにキャスト

$str = "000001";
echo (int)$str;

-> 1

### ltrim();
左端の空白を削除、第二引数で指定した文字を削除

$str = "00000222";
echo ltrim($str, 0);

-> 222

### abs();
絶対値を取得

$str = "0000033";
echo abs($str);

-> 33

int変換だと、$strの値に数値以外の値が入っていた時に、”0″と出力されてしまうので、ltrim();を使うか。
割と奥行きのあるテーマだ。