PHP - 윈디하나의 솔라나라
|
Personal HomePage(개인용 홈페이지)으로 불렸지만, 지금은 개인용이라 하기엔 비교도 안될정도로 커졌기 때문에
PHP: Hypertext Preprocessor으로 변경했다.
FPM의 상태를 볼 수 있는 페이지다. php-fpm.conf
에서 pm.status_path
에 지정된 URL로 접속하면 아래와 같은 화면을 볼 수 있다.
좀 더 상세한 정보를 보려면 URL에 ?full
을 붙여 조회해보자.
Xdebug 는 PHP용 디버깅 툴이다. PHP의 ZEND 확장으로 동작한다. 변수 덤프를 포함해, 스택 추적과 프로파일링, 커버리지등 많은 기능을 제공해주고 있다.
아래와 같이 설치할 수 있다.
windy@wl ~/src $ wget https://xdebug.org/files/xdebug-2.6.1.tgz windy@wl ~/src $ tar xvfz xdebug-2.6.1.tgz windy@wl ~/src $ cd xdebug-2.6.1 windy@wl ~/src/xdebug-2.6.1 $ /usr/local/php/bin/phpize windy@wl ~/src/xdebug-2.6.1 $ ./configure CFLAGS="-m64" --with-php-config=/usr/local/php/bin/php-config windy@wl ~/src/xdebug-2.6.1 $ make windy@wl ~/src/xdebug-2.6.1 $ sudo make install windy@wl ~/src/xdebug-2.6.1 $ sudo vi /usr/local/php/lib/php.ini ... [xdebug] # 반드시 zend_extension = opcache.so 이후에 로드 되어야 한다. zend_extension = xdebug.so windy@wl ~/src/xdebug-2.6.1 $ sudo /etc/init.d/php-fpm restart
설치 후 phpinfo()
를 확인해보면, 아래와 같이 Xdebug 확장이 설치되었다고 표시된다.
Xdebug 에서 기본으로 배포하는 debugclient
를 설치하자.
windy@wl ~/src/xdebug-2.6.1 $ cd debugclient windy@wl ~/src/xdebug-2.6.1/debugclient $ ./configure CFLAGS="-m64 -I/usr/local/include" LDFLAGS="-R/usr/local/lib" --with-libedit windy@wl ~/src/xdebug-2.6.1/debugclient $ make windy@wl ~/src/xdebug-2.6.1/debugclient $ sudo make install
var_dump()
함수 오버라이드를 비활성화하고, 원격 디버그를 허용하도록 설정한다. 모든 설정사항은 XDEBUG EXTENSION FOR PHP | DOCUMENTATION을 참고하자.
windy@wl ~ $ sudo vi /usr/local/php/lib/php.ini ... xdebug.overload_var_dump=0 xdebug.remote_enable=On xdebug.remote_host=127.0.0.1 xdebug.remote_port=9000 xdebug.remote_log=/usr/local/php/var/log/xdebug.log xdebug.idekey=IDEKEY 1)1)
IDEKEY
는 임의로 정한다. 외부에서 유추하지 못하는 값으로 정해야 한다.
우선 디버그 클라이언트를 띄운다.
windy@wl ~ $ debugclient Xdebug Simple DBGp client (0.12.0) Copyright 2002-2018 by Derick Rethans. - libedit support: enabled Creating a socket for IPv4. Waiting for debug server to connect on port 9000.브라우저를 열어서 디버그하고자 할 스크립트를 실행시킨다. PHP 스크립트 실행시 실행시
XDEBUG_SESSION_START=IDEKEY
파라메터를 반드시 전달해야 한다. 일반적인 경우 http://hostname/filename.php?XDEBUG_SESSION_START=IDEKEY
과 같은 형태가될 것이다. 브라우저에서 요청하면 debugclient 에 아래와 같은 메시지가 뜨면서 커맨드 모드로 전환된다. 아래 예제는 단순히 프로세스를 실행하는 예제다.
... Connect <?xml version="1.0" encoding="iso-8859-1"?> <init xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" fileuri="file:///export/home/windy/solanararoot/sr/admin/phpi.php" language="PHP" protocol_version="1.0" appid="6995" idekey="IDEKEY"><engine version="2.3.1"><![CDATA[Xdebug]]></engine><author><![CDATA[Derick Rethans]]></author><url><![CDATA[http://xdebug.org]]></url><copyright><![CDATA[Copyright (c) 2002-2015 by Derick Rethans]]></copyright></init> (cmd) run -i 6995 <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" command="run" transaction_id="6995" status="stopping" reason="ok"></response> Disconnect Waiting for debug server to connect.
XDEBUG_SESSION_START
값이 자동으로 전송된다. 브라우저를 끄고 다시 켜거나 쿠키를 지워야 한다.OpCache가 설치되어있지 않은 경우 아래와 같이 설치할 수 있다.
root@wl ~/src # wget http://pecl.php.net/get/zendopcache-7.0.5.tgz root@wl ~/src # tar xvfz zendopcache-7.0.5.tgz root@wl ~/src # cd zendopcache-7.0.5 root@wl ~/src/zendopcache-7.0.5 # /usr/local/php/bin/phpize root@wl ~/src/zendopcache-7.0.5 # ./configure --with-php-config=/usr/local/php/bin/php-config --enable-opcache root@wl ~/src/zendopcache-7.0.5 # make root@wl ~/src/zendopcache-7.0.5 # make install
설정은 아래와 같이 한다.
root@wl ~ # vi /usr/local/php/lib/php.ini [opcache] zend_extension = opcache.so opcache.enable = 1 opcache.enable_cli = 1 opcache.fast_shutdown = 1 opcache.interned_strings_buffer = 8 opcache.max_accelerated_files = 4000 opcache.memory_consumption = 128 opcache.revalidate_freq = 60
OpCache 는 Zend Extension
으로 등록해야 한다. Extension
이 아니다. Extension
과 Zend Extension
과의 차이점은 PHP vs Zend extensions을 참고하자.
Rasmus Lerdorf가 만든 opcache-status도 같이 설치해 사용해보자. opcache.php
파일 하나만 복사하면 실행할 수 있기 때문에 설치도 쉽다. 아래와 같이 OpCache 에 대한 정보를 볼 수 있다.
아래와 같이 설치할 수 있다.
root@wl ~/src # wget https://pecl.php.net/get/apcu-5.1.11.tgz root@wl ~/src # tar xvfz apcu-5.1.11.tgz root@wl ~/src # cd apcu-5.1.11 root@wl ~/src/apcu-5.1.11 # /usr/local/php/bin/phpize root@wl ~/src/apcu-5.1.11 # ./configure CFLAGS="-m64" --with-php-config=/usr/local/php/bin/php-config root@wl ~/src/apcu-5.1.11 # make root@wl ~/src/apcu-5.1.11 # make install
설정은 아래와 같이 한다. 모든 설정 항목은 APC User Cache을 참조하자.
root@wl ~ # vi /usr/local/php/lib/php.ini extension = apcu.so apc.shm_size = "64M" root@wl ~ # /etc/init.d/php-fpm restart
정상적으로 설치되면 phpinfo()
에서 아래와 같이 표시된다.
소스 패키지에 apc.php
가 있다. 이 파일을 실행시키면 APCu 의 현재 상태를 볼 수 있다. 아래와 같이 나온다.
아래와 같이 설치할 수 있다.
root@wl ~/src # wget http://xcache.lighttpd.net/pub/Releases/3.2.0/xcache-3.2.0.tar.bz2 root@wl ~/src # tar xvfj xcache-3.2.0.tar.bz2 root@wl ~/src # cd xcache-3.2.0 root@wl ~/src/xcache-3.2.0 # /usr/local/php/bin/phpize root@wl ~/src/xcache-3.2.0 # ./configure \ --with-php-config=/usr/local/php/bin/php-config \ --enable-xcache-constant \ --enable-xcache-optimizer \ --enable-xcache-coverager \ --enable-xcache-assembler \ --enable-xcache-disassembler \ --enable-xcache-encoder \ --enable-xcache-decoder root@wl ~/src/xcache-3.2.0 # make root@wl ~/src/xcache-3.2.0 # make install root@wl ~/src/xcache-3.2.0 # mkdir /usr/local/apache2/htdocs/xcacheadmin root@wl ~/src/xcache-3.2.0 # cp -R htdocs/* /usr/local/apache2/htdocs/xcacheadmin
설정은 아래와 같이 한다.
root@wl ~ # vi /usr/local/php/lib/php.ini extension_dir = "/usr/local/php/lib/php/extensions/" enable_dl = On extension = xcache.so xcache.size = 1M xcache.var_size = 1M ;xcache.cacher = Off ;xcache.optimizer = Off ;xcache.admin.enable_auth = Off xcache.admin.user="admin" xcache.admin.pass="md5(패스워드)한 값"
XCache 관리자 페이지에 접속해 아래와 같이 현재 상태를 볼 수 있다.
root@wl ~ # dtrace -l -m php ID PROVIDER MODULE FUNCTION NAME 51555 php25002 php dtrace_compile_file compile-file-entry 51556 php25002 php dtrace_compile_file compile-file-return 51557 php25002 php zend_error error 51558 php25002 php ZEND_CATCH_SPEC_CONST_CV_HANDLER exception-caught 51559 php25002 php zend_throw_exception_internal exception-thrown 51560 php25002 php dtrace_execute_internal execute-entry 51561 php25002 php dtrace_execute_ex execute-entry 51562 php25002 php dtrace_execute_internal execute-return 51563 php25002 php dtrace_execute_ex execute-return 51564 php25002 php dtrace_execute_ex function-entry 51565 php25002 php dtrace_execute_ex function-return 51566 php25002 php php_request_shutdown request-shutdown 51567 php25002 php php_request_startup request-startup
root@wl ~ # dtrace -l -m php-fpm ID PROVIDER MODULE FUNCTION NAME 51351 php28979 php-fpm dtrace_execute_ex execute-return 51352 php28979 php-fpm dtrace_execute_ex function-entry 51353 php28979 php-fpm dtrace_execute_ex function-return 51354 php28979 php-fpm php_request_shutdown request-shutdown 51355 php28979 php-fpm php_request_startup request-startup 51412 php28979 php-fpm dtrace_compile_file compile-file-entry 51542 php28979 php-fpm zend_throw_exception_internal exception-thrown 51543 php28979 php-fpm dtrace_execute_internal execute-entry 51544 php28979 php-fpm dtrace_execute_ex execute-entry 51545 php28979 php-fpm dtrace_execute_internal execute-return 51548 php28979 php-fpm dtrace_compile_file compile-file-return 51549 php28979 php-fpm zend_error error 51550 php28979 php-fpm ZEND_CATCH_SPEC_CONST_CV_HANDLER exception-caughtPHP-FPM의 프로세스가 한개가 아니라는 것에 주의하자.
php_dtrace.d | (2,609 바이트) |
#!/usr/sbin/dtrace -Zs #pragma D option quiet php*:::compile-file-entry { printf("PHP compile-file-entry\n"); printf(" compile_file %s\n", copyinstr(arg0)); printf(" compile_file_translated %s\n", copyinstr(arg1)); } php*:::compile-file-return { printf("PHP compile-file-return\n"); printf(" compile_file %s\n", copyinstr(arg0)); printf(" compile_file_translated %s\n", copyinstr(arg1)); } php*:::error { printf("PHP error\n"); printf(" errormsg %s\n", copyinstr(arg0)); printf(" request_file %s\n", copyinstr(arg1)); printf(" lineno %d\n", (int)arg2); } php*:::exception-caught { printf("PHP exception-caught\n"); printf(" classname %s\n", copyinstr(arg0)); } php*:::exception-thrown { printf("PHP exception-thrown\n"); printf(" classname %s\n", copyinstr(arg0)); } php*:::execute-entry { printf("PHP execute-entry\n"); printf(" request_file %s\n", copyinstr(arg0)); printf(" lineno %d\n", (int)arg1); } php*:::execute-return { printf("PHP execute-return\n"); printf(" request_file %s\n", copyinstr(arg0)); printf(" lineno %d\n", (int)arg1); } php*:::function-entry { printf("PHP function-entry\n"); printf(" function_name %s\n", copyinstr(arg0)); printf(" request_file %s\n", copyinstr(arg1)); printf(" lineno %d\n", (int)arg2); printf(" classname %s\n", copyinstr(arg3)); printf(" scope %s\n", copyinstr(arg4)); } php*:::function-return { printf("PHP function-return\n"); printf(" function_name %s\n", copyinstr(arg0)); printf(" request_file %s\n", copyinstr(arg1)); printf(" lineno %d\n", (int)arg2); printf(" classname %s\n", copyinstr(arg3)); printf(" scope %s\n", copyinstr(arg4)); } php*:::request-shutdown { printf("PHP request-shutdown\n"); printf(" file %s\n", copyinstr(arg0)); printf(" request_uri %s\n", copyinstr(arg1)); printf(" request_method %s\n", copyinstr(arg2)); } php*:::request-startup { printf("PHP request-startup\n"); printf(" file %s\n", copyinstr(arg0)); printf(" request_uri %s\n", copyinstr(arg1)); printf(" request_method %s\n", copyinstr(arg2)); }
php_oci.d | (1,814 바이트) |
#!/usr/sbin/dtrace -Zs #pragma D option quiet php*:::oci8-connect-entry { printf("%lld: PHP connect-entry\n", walltimestamp); printf(" credentials=\"%s@%s\"\n", arg0 ? copyinstr(arg0) : "", arg1 ? copyinstr(arg1) : ""); printf(" charset=\"%s\"\n", arg2 ? copyinstr(arg2) : ""); printf(" session_mode=%ld\n", (long)arg3); printf(" persistent=%d\n", (int)arg4); printf(" exclusive=%d\n", (int)arg5); } php*:::oci8-connect-return { printf("%lld: PHP oci8-connect-return\n", walltimestamp); printf(" connection=0x%p\n", (void *)arg0); } php*:::oci8-connection-close { printf("%lld: PHP oci8-connect-close\n", walltimestamp); printf(" connection=0x%p\n", (void *)arg0); } php*:::oci8-error { printf("%lld: PHP oci8-error\n", walltimestamp); printf(" status=%d\n", (int)arg0); printf(" errcode=%ld\n", (long)arg1); } php*:::oci8-check-connection { printf("%lld: PHP oci8-check-connection\n", walltimestamp); printf(" connection=0x%p\n", (void *)arg0); printf(" client_id=\"%s\"\n", arg1 ? copyinstr(arg1) : ""); printf(" is_open=%d\n", arg2); printf(" errcode=%ld\n", (long)arg3); printf(" server_status=%lu\n", (unsigned long)arg4); } php*:::oci8-sqltext { printf("%lld: PHP oci8-sqltext\n", walltimestamp); printf(" connection=0x%p\n", (void *)arg0); printf(" client_id=\"%s\"\n", arg1 ? copyinstr(arg1) : ""); printf(" statement=0x%p\n", (void *)arg2); printf(" sql=\"%s\"\n", arg3 ? copyinstr(arg3) : ""); } php*:::oci8-execute-mode { printf("%lld: PHP oci8-execute-mode\n", walltimestamp); printf(" connection=0x%p\n", (void *)arg0); printf(" client_id=\"%s\"\n", arg1 ? copyinstr(arg1) : ""); printf(" statement=0x%p\n", (void *)arg2); printf(" mode=0x%x\n", arg3); }
php_call.d | (1,608 바이트) |
/* Based on https://blogs.oracle.com/bmc/entry/dtrace_and_php_demonstrated modified with printing timestamp */ #pragma D option quiet self int indent; php$target:::function-entry /copyinstr(arg0) == "launch"/ { self->follow = 1; } php$target:::function-entry /self->follow/ { printf("%*s", self->indent, ""); printf("-> %-20s %*sphp\n", copyinstr(arg0), 46 - self->indent, ""); self->indent += 2; self->start = timestamp; } php$target:::function-return /self->follow/ { self->indent -= 2; printf("%*s", self->indent, ""); printf("<- %-20s %*sphp %20d\n", copyinstr(arg0), 46 - self->indent, "", timestamp - self->start); } pid$target:libc.so.1::entry /self->follow/ { printf("%*s", self->indent, ""); printf("-> %-20s %*s%s\n", probefunc, 46 - self->indent, "", probemod); self->indent += 2; } pid$target:libc.so.1::return /self->follow/ { self->indent -= 2; printf("%*s", self->indent, ""); printf("<- %-20s %*s%s\n", probefunc, 46 - self->indent, "", probemod); } php$target:::function-return /copyinstr(arg0) == "launch"/ { self->follow = 0; exit(0); } fbt:genunix::entry /self->follow/ { printf("%*s", self->indent, ""); printf("-> %-20s %*skernel\n", probefunc, 46 - self->indent, ""); self->indent += 2; } fbt:genunix::return /self->follow/ { self->indent -= 2; printf("%*s", self->indent, ""); printf("<- %-20s %*skernel\n", probefunc, 46 - self->indent, ""); }
root@wl ~ # dtrace -s ./php_call.d -p xxxx
PHP 5.4 부터 PHP 자체에 Build-in 개발 서버를 지원한다.
php -S 주소:포트 [-t 문서루트]
문서 루트를 지정하지 않으면, 현재 디렉토리가 문서의 루트가 된다. 따라서 루트 디렉토리에서 PHP Build-in 서버를 옵션 없이 실행해서는 안된다.
root@wl ~ # mkdir phpServer root@wl ~ # cd phpServer root@wl ~/phpServer # vi index.php <?php phpinfo.php ?> root@wl ~/phpServer # /usr/local/php/bin/php -S 211.204.126.106:8009 PHP 5.6.0 Development Server started at Mon Sep 15 20:08:35 2014 Listening on http://211.204.126.106:8009 Document root is /export/home/windy/s Press Ctrl-C to quit. [Mon Sep 15 00:00:00 2014] 1.221.41.190:61865 [200]: /
성능은 그저 그런 수준이지만, 개발자를 위한 디버깅용으로는 손색이 없다고 생각한다.
PECL은 PHP 확장의 저장소이다. PHP 공식적인것도 있지만 커뮤니티에 의해 운영되기 때문에 실험적인 프로젝트도 많다. 몇가지 유용하다고 생각하는 모듈에 대해 설명한다.
windy@wl ~/src $ wget https://pecl.php.net/get/igbinary-2.0.5.tgz windy@wl ~/src $ tar xvfz igbinary-2.0.5.tgz windy@wl ~/src $ cd igbinary-2.0.5 windy@wl ~/src/igbinary-2.0.5 # /usr/local/php/bin/phpize windy@wl ~/src/igbinary-2.0.5 # CFLAGS="-m64 -xc99" ./configure --with-php-config=/usr/local/php/bin/php-config --enable-igbinary windy@wl ~/src/igbinary-2.0.5 # make windy@wl ~/src/igbinary-2.0.5 # make install windy@wl ~/src/igbinary-2.0.5 # vi /usr/local/php/lib/php.ini extension=igbinary.so session.serialize_handler=igbinary ;igbinary.compact_strings=Off ;apc.serializer=igbinary
설치가 완료되면 PHP를 재시작한다. phpinfo() 에 아래와 같은 문구가 보이면 정상적으로 설치된 것이다.
테스트
php_serialize.php | (591 바이트) |
#!/usr/local/php/bin/php <?php $obj = array( "key" => "value" ); echo "Original Objects\n"; var_dump($obj); echo "\nPHP Serialize\n"; $ser = serialize($obj); var_dump($ser); $unser = unserialize($ser); var_dump($unser); echo "\nJSON Encode/Decode\n"; $ser = json_encode($obj); var_dump($ser); $unser = json_decode($ser); var_dump($unser); if (extension_loaded("igbinary")) { echo "\nigbinary Serialize\n"; $ser = igbinary_serialize($obj); var_dump($ser); $unser = igbinary_unserialize($ser); var_dump($unser); } else { echo "\nigbinary not loaded.\n"; } ?>
root@wl ~ $ ./php_serialize.php Original Objects array(1) { 'key' => string(5) "value" } PHP Serialize string(28) "a:1:{s:3:"key";s:5:"value";}" array(1) { 'key' => string(5) "value" } JSON Encode/Decode string(15) "{"key":"value"}" class stdClass#1 (1) { public $key => string(5) "value" } igbinary Serialize string(18) "\000\000\000keyvalue" array(1) { 'key' => string(5) "value" }
RSS ATOM XHTML 5 CSS3 |
Copyright © 2004-2025 Jo HoSeok. All rights reserved. |