- 記事一覧 >
- ブログ記事

php→pythonのトランスパイル 人力読み替え編
はじめに
PHPのプログラム(wiringpi-php-bme280(GitHub))を同一の機能のままPythonに変換し、wiringpi-python-bme280(GitHub)に公開しました。
別記事の「php→pythonのトランスパイル」のプログラムを使って文法をある程度変換→人力で変換と作業しましたが、結局、ほとんどが人力作業だったような気がします。今回、備忘録的にphp→pythonの変換例を列挙していきます。
細かい説明は省略し、変換前、変換後の列挙に留めます。順番は適当です。場合によっては等価ではないこともありますので、PHP、Python双方を理解して参考程度としてください。また、この記事中にあってもwiringpi-python-bme280では、他の方法で書き換えたものもあります。
検証環境は、
Raspbian GNU/Linux 10 (buster)
Python 3.7.3
PHP 7.3.29-1になります。
【目次】
define、require、&&、argc、!、strcasecmp、intval、file_get_contents、posix_kill、is_file、pcntl_fork、die、$_SERVER、empty、mkdir、$_REQUEST、opendir readdir、is_file、preg_match、[] 配列追加、rsort、substr、isset、file、array_shift、explode、floatval、連想配列のキーと値追加、trim、json_encode、curl_init、curl_setopt、$_POST、is_array、foreach、引数のデフォルト値、array()、apache_request_headers、strlen、static、$GLOBALS、printf、flush、strpos、header、curl_exec、curl_close、usleep、time、strftime、sprintf、file_put_contents、fseek、ftell、pcntl_signal、無名関数、__construct、protected、for、>>、++、文字コード指定、ord、三項演算子
define
define( "LOG_DIR", "/var/log/bme280log/" );↓
LOG_DIR = "/var/log/bme280log/"require
require( "bme280.inc" );↓
import bme280_inc※bme280_inc.py読み込み
&&
if ( $argc > 1 && !strcasecmp( $argv[1], "stop" ) ) {↓
if len(sys.argv) > 1 and sys.argv[1].lower() != "stop":argc
if ( $argc > 1 && !strcasecmp( $argv[1], "stop" ) ) {↓
if len(sys.argv) > 1 and sys.argv[1].lower() != "stop":!
if文のエクスクラメーション/ビックリマーク
if ( $argc > 1 && !strcasecmp( $argv[1], "stop" ) ) {↓
if len(sys.argv) > 1 and sys.argv[1].lower() != "stop":if( !is_file( "$dir/$file" ) ) continue;↓
if not os.path.isfile(os.path.join(dir, file)):
continuestrcasecmp
if ( !strcasecmp( $_SERVER["REQUEST_METHOD"], "POST" ) ) {↓
if request.environ["REQUEST_METHOD"].upper() == "POST":※lowerまたは、upper
intval
$pid = intval( file_get_contents( PID_FILE ) );↓
pid = int(file_get_contents(PID_FILE))file_get_contents
$pid = intval( file_get_contents( PID_FILE ) );↓
def file_get_contents(filename):
with open(filename) as f:
return f.read()
pid = int(file_get_contents(PID_FILE))posix_kill
$pid = intval( file_get_contents( PID_FILE ) );
posix_kill( $pid );↓
import os
import signal
os.kill(pid, signal.SIGTERM)is_file
if is_file(PID_FILE):↓
if os.path.isfile(PID_FILE):pcntl_fork
pid = pcntl_fork()
if pid==-1:
die("fork できません")↓
try:
pid = os.fork()
except OSError:
print("fork できません")
sys.exit()die
die("fork できません")↓
print("fork できません")
sys.exit()$_SERVER
if ( empty( $_SERVER["REQUEST_METHOD"] ) || $_SERVER["REQUEST_METHOD"] != "POST" ) {↓
from flask import request
if (
request.environ["REQUEST_METHOD"] is None
or request.environ["REQUEST_METHOD"] != "POST"
):empty
if ( empty( $_SERVER["REQUEST_METHOD"] ) || $_SERVER["REQUEST_METHOD"] != "POST" ) {↓
if (
request.environ["REQUEST_METHOD"] is None
or request.environ["REQUEST_METHOD"] != "POST"
):if ( !empty( $GLOBALS["CHUNKED"] ) ) {↓
if hasattr(builtins, "CHUNKED") and builtins.CHUNKED:mkdir
mkdir( $dir, 0755 );↓
os.mkdir(dir)
os.chmod(dir, 0o755)$_REQUEST
if ( $_REQUEST["TYPE"] == "FILELIST" ) {↓
from flask import request
if request.form.get("TYPE") == "FILELIST":opendir readdir
$dp = opendir( $dir );
if ( $dp !== false ) {
while( ( $file = readdir( $dp ) ) !== false ) {↓
for f in os.listdir(dir):is_file
if( !is_file( "$dir/$file" ) ) continue;↓
if not os.path.isfile(os.path.join(dir, f)):preg_match
if( preg_match( "/\.log$/", $file ) ) {↓
import re
matches = re.search('\.log$', file)※大文字小文字無視フラグ有りの場合
if ( preg_match( "/^Transfer\-Encoding\:\s+chunked/i", $head ) ) {↓
if re.search(
r"^Transfer\-Encoding\:\s+chunked", head, re.IGNORECASE
):[] 配列追加
$files[] = $file;↓
files.append(file)rsort
rsort( $files );↓
files.sort(reverse=True)substr
$date = substr( $file, 0, 4 ) . "/" .↓
date = file[0:4] + "/" ※file[0:4]は、file[:4]でも良い。
isset
if( isset( $_REQUEST["DATE"] ) ) {↓
if request.form.get("DATE") is not None:file
$logdata = file( $file, FILE_IGNORE_NEW_LINES );
//FILE_IGNORE_NEW_LINES : 配列の各要素の最後に改行文字が含まれない↓
try:
with open(file,"r") as f:
logdata = f.read().splitlines()
except:
passarray_shift
array_shift( $logdata );↓
logdata.pop(0)explode
$val = explode( "\t", $data );↓
val = data.split("\t")floatval
$result[$val[1]] = array(
floatval( $val[2] ), floatval( $val[3] ), floatval( $val[4] )
);↓
result[val[1]] = [float(val[2]), float(val[3]), float(val[4])]連想配列のキーと値追加
$result[$val[1]] = array(
floatval( $val[2] ), floatval( $val[3] ), floatval( $val[4] )
);↓
result[val[1]] = [float(val[2]), float(val[3]), float(val[4])]trim
$data = trim( file_get_contents( $file ) );↓
data = file_get_contents(file).strip()json_encode
$text = json_encode( $result, JSON_UNESCAPED_UNICODE );
//JSON_UNESCAPED_UNICODE:マルチバイト Unicode 文字をそのままの形式で扱います (デフォルトでは \uXXXX にエスケープします)。↓
import json
text = json.dumps(result, ensure_ascii=False)↓
from flask import Flask
app = Flask(__name__)
app.config["JSON_AS_ASCII"] = False
return jsonify(result)curl_init
$ch = curl_init();↓
import pycurl
ch = pycurl.Curl()curl_setopt
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 );↓
ch.setopt(pycurl.SSL_VERIFYPEER, False)$_POST
$param = array_to_str( $_POST );↓
from flask import request
param = array_to_str(request.form)is_array
if ( !is_array( $value ) ) {↓
if not isinstance(value, (list, tuple, set, dict)):foreach
foreach( $value as $k => $v ) {↓
for k, v in value:引数のデフォルト値
function array_to_str( $value, $key = "" ) {↓
def array_to_str(value, key=""):array()
$headers = array();↓
headers = []apache_request_headers
foreach ( apache_request_headers() as $name => $value ) {↓
import os
for name, value in os.environ.iteritems():
if name.startswith("HTTP_")↓
from flask import request
for name, value in request.headers:strlen
$ln = strlen( $buffer );↓
ln = len(buffer)static
function call_back( $ch, $buffer ) {
$ln = strlen( $buffer );
static $start_head = false;
static $start_body = false;
static $save = "";↓
def static_vars(**kwargs):
def decorate(func):
for k in kwargs:
setattr(func, k, kwargs[k])
return func
return decorate
@static_vars(start_head=False,start_body=False,save="")
def call_back(ch, buffer):
ln = len(buffer)$GLOBALS
スーパーグローバル(super global)
if ( !empty( $GLOBALS["CHUNKED"] ) ) {↓
import builtins
if hasattr(builtins, "CHUNKED") and builtins.CHUNKED:↓
メモリに留まり続けるため、globalステートメント使用
global chunked_flag
chunked_flag = False
def call_back(buffer):
ln = len(buffer)
global chunked_flag
if call_back.start_body:
if chunked_flag:printf
printf( "%x\r\n", strlen( $buffer ) );↓
print("%x\r\n" % (len(buffer)), end='')flush
flush();↓
import sys
sys.stdout.flush()↓
from flask import flash
flash('xxx')※未検証
strpos
if ( ( $pos = strpos( $buffer, "\r\n" ) ) === false ) {↓
pos = buffer.find("\r\n")
if pos > 0:header
header(head)↓
print(head)
print()header('HTTP/1.1 400 Bad Request');
echo "Bad Request";
exit;↓
from flask import abort
abort(400, 'Bad Request')header( 'HTTP', true, 403 );
echo "Could not connect to server\n'{$_REQUEST["REQUEST_URL"]}'\r\n";↓
return "Could not connect to server\n'" + request.form.get("REQUEST_URL") + "'\r\n",403Flaskでjsonを返す場合は、以下。
$text = json_encode( $result, JSON_UNESCAPED_UNICODE );
header( "Content-Type: application/json; charset=utf-8" );
header( "Content-Length: " . strlen( $text ) );
echo $text;↓
from flask import jsonify
app.config["JSON_AS_ASCII"] = False
@app.route("/getlogdata")
def getlogdata():
return jsonify(result)curl_exec
if ( curl_exec( $ch ) !== true ) {
# エラー処理↓
try:
ch.perform()
except Exception:
# エラー処理curl_close
curl_close( $ch );↓
ch.close()usleep
usleep( 100000 );↓
import time
def usleep(x):
time.sleep(x/1000000.0)
usleep(100000)↓
import time
time.sleep(100000 / 1000000.0)time
$tm = time();↓
import time
tm = int(time.time())strftime
$text .= strftime( "%Y/%m/%d\t", $tm );↓
import datetime
dt_now = datetime.datetime.now()
text += dt_now.strftime( "%Y/%m/%d\t")sprintf
$text .= sprintf( "%.2f\t", $bme280->temperature + 0.005 );↓
text += "{0:.2f}\t".format(bme280.temperature + 0.005)file_put_contents
LOCK_EX(排他ロック)有り
file_put_contents( $log_file, $text, LOCK_EX );↓
import fcntl
def file_put_contents(filename, data):
with open(filename, "w") as f:
f.write(data)
def touch(filename):
if os.path.exists(filename):
# os.utime(fname, None)
pass
else:
open(filename, "a").close()
def file_put_contents_ex(filename, data):
touch(filename)
with open(filename) as lockfile:
fcntl.flock(lockfile.fileno(), fcntl.LOCK_EX)
try:
file_put_contents(filename, data)
finally:
fcntl.flock(lockfile.fileno(), fcntl.LOCK_UN)fseek
$fp = fopen( $log_file, "a" );
if ( $fp !== false ) {
fseek( $fp, 0, SEEK_END );↓
with open(log_file, "a") as f:
pos = f.tell()※"a"フラグのopenで自動的にSEEK_ENDになる。
ftell
$pos = ftell( $fp );↓
pos = f.tell()pcntl_signal
pcntl_signal( SIGTERM, function( $signo, $siginfo ) {
$GLOBALS["lcd"]->lcdClear();
$GLOBALS["lcd"]->lcdDisplay( false );
unlink( PID_FILE );
exit;
} );↓
signal.signal(
signal.SIGTERM,
lambda _signo, _stack_frame: [lcd.lcdClear(), lcd.lcdDisplay(False), os.unlink(PID_FILE), sys.exit()],
)※signal.signalの2つ目の引数のcallback関数は、引数を2つ取る。
無名関数
pcntl_signal( SIGTERM, function( $signo, $siginfo ) {
$GLOBALS["lcd"]->lcdClear();
$GLOBALS["lcd"]->lcdDisplay( false );
unlink( PID_FILE );
exit;
} );↓
signal.signal(
signal.SIGTERM,
lambda _signo, _stack_frame: [lcd.lcdClear(), lcd.lcdDisplay(False), os.unlink(PID_FILE), sys.exit()],
)__construct
function __construct( $addr, $rows = 2, $cols =16, $bits = 4 ) {↓
def __init__(self, addr, rows=2, cols=16, bits=4):protected
protected $rows;↓
_rows = 2for
for ( $i = 0; $i < 8; $i ++ ) {↓
for i in range(8):>>
ビット演算子右シフト
$this->put4Command( $func >> 4);↓
self.put4Command(func >> 4)++
インクリメンタル演算子
if ( ++ $this->cx >= $this->cols ) {↓
self._cx += 1
if self._cx >= self._cols: 文字コード指定
\xdf sjis文字コード指定
$lcd->lcdPuts( sprintf( "%5.2f\xdfC %5.2f%%", $bme280->temperature + 0.005, $bme280->humidity + 0.005 ) );↓
lcd.lcdPuts(
"{0:5.2f}{1}C {2:5.2f}%".format(
bme280.temperature + 0.005, b"\xdf".decode('sjis'), bme280.humidity + 0.005
)
)※ \xdf は、半角の丸です。 1602A LCDは、ANKコードを使用するため、℃の表示にsjisの半角丸を使っています。
【 ANKコード 】
ASCIIコード(0x00-0x7F)を 0x00-0xFF まで拡張して、半角カナを含めたものです。
アルファベット (Alphabet)、数字 (Numerical digit)、片仮名 (Katakana) の頭文字から「ANKコード」と呼ばれるようになりました。
後に「JIS X 0201」 として正式に定義されました。
「JIS X 0201」の俗称が「ANKコード」ということになります。
ord
ord — 文字列の先頭バイトを、0 から 255 までの値に変換する
$this->lcdPutchar( Ord( $string[$n] ) );↓
self.lcdPutchar(ord(string[n]))※python3の場合、全角文字が1文字としてカウントされて、意図した動きでは無かったため、以下のように対応
for ( $n = 0; $n < strlen( $string ); $n ++ ) {
$this->lcdPutchar( Ord( $string[$n] ) );
}↓
def lcdPuts(self, string):
chars = bytearray(string.encode("sjis"))
for n in range(len(chars)):
self.lcdPutchar(chars[n])三項演算子
$d =( $data & ( 0x01 << $i ) ) ? WiringPi::HIGH : WiringPi::LOW;↓
d = wiringpi.HIGH if (data & (0x10 << i)) else wiringpi.LOW※trueならHIGH、falseならLOW

その他、宣伝、誹謗中傷等、当方が不適切と判断した書き込みは、理由の如何を問わず、投稿者に断りなく削除します。
書き込み内容について、一切の責任を負いません。
このコメント機能は、予告無く廃止する可能性があります。ご了承ください。
コメントの削除をご依頼の場合はTwitterのDM等でご連絡ください。






