PHP cli (5.3.3)로 스크립트를 하나 만들어놨다.

파일 처리한 후 rename 함수로 백업 경로로 옮기는 스크립트인데

용량 확보와 속도 개선을 위해 추가 디스크를 마운트 시켜놓고 나니 이런 오류가 발생했다.

[PHP] PHP Warning:  rename(/AAA/XXX,/BBB/XXX):
Operation not permitted in XXX.php on line XX

황당하게도 처리는 제대로 되었고 경고만 뜬다.


http://kr1.php.net/manual/en/function.rename.php


원인을 찾아보니 php 의 rename은 리눅스의 rename 명령을 이용하는 것이다보니 본래는 디스크간 이동을 위한 것이 아니다.

그러므로 디스크간 이동을 위해서는 system 이나 exec 함수로 식으로 수정하거나


exec("mv /AAA/XXX /BBB/XXX") ;

or

if(copy('/AAA/XXX', '/BBB/XXX')==TRUE) unlink('/AAA/XXX');

식으로 수정하면 경고 없이 깔끔하게 된다.

Posted by freezn

zend_parse_parameters 함수를 사용합니다.

아마 매크로겠지만 그런 것 까지 신경쓰진 않습니다. ㅎㅎ


함수 만들기 기본 설명, 상세 파라미터 종류 들은 http://www.php.net/manual/en/internals2.funcs.php 에서 볼 수 있습니다..만 퍼옵니다.

 Spec

 Type

 Locals

 a

 array

 zval*

 A

 array or object

 zval*

 b

 boolean

 zend_bool

 C

 class

 zend_class_entry*

 d

 double

 double

 f

 function

 zend_fcall_info*, zend_fcall_info_cache*

 h

 array

 HashTable*

 H

 array or object

 HashTable*

 l

 long

 long

 L

 long (limits out-of-range LONG_MAX/LONG_MIN)

 long

 o

 object

 zval*

 O

 object (of specified zend_class_entry)

 zval*, zend_class_entry*

 p

 string (a valid path)

 char*, int

 r

 resource

 char*

 s

 string

 char*, int

 z

 mixed

 zval*

 Z

 mixed

 zval**


3번째 파라메터 문자열은 어떤 변수타입들을 받을지, 4번째 이후는 받을 변수들입니다.

zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "받을변수타입들", &변수1, &변수2, ....)


간단히 예시로 정리하면..

// bool : zend_bool
PHP_FUNCTION(test_func1)
{
	zend_bool bool_test;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &bool_test) == FAILURE) {
		RETURN_NULL();
	}
	
	if(bool_test==1)
	{
		// true
	}
	else
	{
		// false
	}

	RETURN_NULL();
}

// long
PHP_FUNCTION(test_func2)
{
	long long_test;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &long_test) == FAILURE) {
		RETURN_NULL();
	}
	RETURN_NULL();
}

// string
PHP_FUNCTION(test_func3)
{
	char* str_test;
	int str_test_len;
	// 문자열의 경우 파라메터가 무조건 2개임을 명심..
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str_test, &str_test_len) == FAILURE) {
		RETURN_NULL();
	}
	RETURN_NULL();
}



여러개일 경우는 그냥 타입을 여러개 쓰고 문자열같은 경우는 깊이값도 같이 받아주면 됩니다.


// multiple params
PHP_FUNCTION(test_func4)
{
	long a;
	double b;
	zend_bool c;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ldb", &a, &b, &c) == FAILURE) {
		RETURN_NULL();
	}
	RETURN_NULL();
}


// multiple params with string
PHP_FUNCTION(test_func5)
{
	long a;
	double b;
	zend_bool c;
	char * d;
	int d_len;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ldb", &a, &b, &c, &d, &d_len) == FAILURE) {
		RETURN_NULL();
	}
	RETURN_NULL();
}



리턴도 간단합니다.

자세한건 이 링크를 참고하면 되고.. http://docstore.mik.ua/orelly/webprog/php/ch14_08.htm


다른 타입들도 맞춰서 하면 됩니다. 잘 정리되어있네요.

RETURN_RESOURCE(int r);
RETURN_BOOL(int b) ;
RETURN_NULL( );
RETURN_LONG(int l) ;
RETURN_DOUBLE(double d) ;
RETURN_STRING(char *s, int dup) ;
RETURN_STRINGL(char *s, int l, int dup);
RETURN_EMPTY_STRING( );
RETURN_FALSE ;
RETURN_TRUE;
RETVAL_RESOURCE(int r);
RETVAL_BOOL(int b);
RETVAL_NULL( );
RETVAL_LONG(int l);
RETVAL_DOUBLE(double d);
RETVAL_STRING(char *s, int dup);
RETVAL_STRINGL(char *s, int l, int dup);
RETVAL_EMPTY_STRING( );
RETVAL_FALSE;
RETVAL_TRUE;

// return null
PHP_FUNCTION(test_func_ret1)
{
	RETURN_NULL();
}

조금 골치 아픈 건 배열이나 클래스인데 배열만 좀 써보면..

// assoc_array
PHP_FUNCTION(test_func_ret2)
{
	// return_value 는 zval* 타입입니다.
	// 선언은? 글로벌인지 로컬인지 모르겠지만 어딘가에서 해놨나봅니다. 다시 선언하면 오류납니다.
	array_init(return_value);

	add_assoc_long(return_value, "x", 123);
	add_assoc_double(return_value, "y", 456.7);
}

이러면 됩니다.

따로 return 명령을 내리지 않아도 리턴이 됩니다.

PHP에서 받아보면 이런 형태죠

<?php
$ret = test_func_ret2();
var_dump($ret);
?>

array(2) {

["x"]=>

int(123)

["y"]=>

float(456.7)

}


그럼 배열 안의 배열은 ? (subarray)

어떤 함수가 있는지는 PHP 페이지에 있습니다. http://www.php.net/manual/ro/internals2.variables.arrays.php


// sub_array PHP_FUNCTION(test_func_ret3) { zval *subarray; // 요걸 하나 만들어둡니다. int i; array_init(return_value); // 당연히 초기화 하고 for(i=0; i<3; i++) // 3개를 추가해보겠습니다. { MAKE_STD_ZVAL(subarray); // 이름봐선 데이터를 널이나 0으로 채워주는 놈인가봅니다... array_init(subarray); // 추가할 서브배열도 초기화하고 // 값들을 집어넣습니다. add_assoc_long(subarray, "x", 123); add_assoc_double(subarray, "y", 456.7); // 리턴할 값에 서브배열을 추가합니다. add_next_index_zval(return_value, subarray); } }


결과를 찍어보면?

<?php
$ret = test_func_ret3();
var_dump($ret);
?>

요렇게 나오겠죠

array(3) {

[0]=>

array(2) {

["x"]=>

int(123)

["y"]=>

float(456.7)

}

[1]=>

array(2) {

["x"]=>

int(123)

["y"]=>

float(456.7)

}

[2]=>

array(2) {

["x"]=>

int(123)

["y"]=>

float(456.7)

}

  }


Posted by freezn

PHP 모듈 작성 시 다음과 같은 오류 메세지가 나오는 경우가 있다.

error: 'PHP_FE_END' undeclared here (not in a function)


1. 

내 상황은 서버가 centos6.3 으로 php 는 rpm으로 설치되어있다.


php-devel 패키지도 설치해놨지만 ext_skel 은 없었고 구글링하다보니 src.rpm 을 던져주는 링크만 나오더라.

https://www.centos.org/forums/viewtopic.php?t=28478


2.

굳이 src.rpm으로 작업하고 싶은 생각은 없어 그냥 php-5.3.3 의 소스를 찾았지만 나오질 않는다.

그냥 php-5.3.28 을 받아 타르볼을 풀고

ext로 들어가 알려진대로


./ext_skel --extname=test_mod


cd test_mod


vi config.m4

10라인, PHP_ARG_WITH(test_mod, for test_mod support,

12라인, [  --with-test_mod             Include test_mod support])

에서 dnl 주석 해제


phpize

./configure

make


3.

뭐 이런 수순으로 스켈레톤을 빌드 해보는데 정의되지 않았다고 오류가 발생한다.

libtool: compile:  cc -I. -I/ ~~~~ :43: error: 'PHP_FE_END' undeclared here (not in a function)

make: *** [test_mod.lo] Error 1


4.

구글링해보니 PHP_FE_END는 php-5.3.10 부터 등장했단다. https://github.com/sqmk/pecl-jsmin/issues/23

이하버전에 호환되는 모듈을 뒤져보니 

{NULL, NULL, NULL}

다행히도 PHP_FE_END 대신 쓰이는 놈이 있다.

덜 게으르면 버전 확인해서 #if 하겠지만 한두개 뒤져봤을 때 PHP 버전 정의가 잘 안뵌다.

여러버전에서 자주 컴파일 할일이 있을 때 까진 그냥 이리 써야겠다.

test_mod.c :

const zend_function_entry test_mod_functions[] = {

PHP_FE(confirm_test_mod_compiled, NULL) /* For testing, remove later. */

//PHP_FE_END /* Must be the last line in test_mod_functions[] */ // PHP 5.3.10 ~

{NULL, NULL, NULL} /* Must be the last line in test_mod_functions[] */ // PHP 5.3.10 under

};


Posted by freezn

환경

CentOS 6.x, Apache, PHP

MATLAB 2011a 로 컴파일된 바이너리, MCR 설치

참고사항

- x64 빌드는 당연히 x86 에서 실행 불가

- 실행 방법은 단순히 exec()

- 당연히 실행 디렉토리와 파일에 실행권한(execute permission) 추가

- 실행디렉토리에는 쓰기권한(write permission) 필요

- mcc build option에 -C 사용 (예: $MATLAB/bin/mcc -m -C -R '-nojvm,-nodisplay' ./mymatlabcode.m)
-- 안하면 다음 에러를 아파치 로그에서 볼 수 있음 : Could not access the MCR component cache.

- 그러고도 보면 안된다. 이유는 아파치 로그 보면 락파일 생성 실패

Could not access preferences directory: '/.matlab/mcr_v715/wave_spec_59B08FCA175BF328CA63A32591F61785'. System error: 'Tried to obtain a lock on a non-existent directory: /.matlab/mcr_v715/.deploy_lock.0'

-- centos 에서 rpm으로 설치한 apache 는 웹에서 접속 시 home directory가 / (root) 로 되어있나보다. (passwd 파일에 있는 경로와 다르다.)

-- 컴파일시 같이 생성된 run_mymatlabcode.sh 파일에 홈경로변수($HOME)를 쓰기 가능한 경로로 지정해버렸다.

-- $HOME=write enabled path

-- .ctf 파일 빼먹으면 안된다


웹에서 실행해보면 지정한 홈경로에 mymablabcode_mcr 디렉토리가 생성(복사?)되고 실행되는걸 볼 수 있다. -_-;;;;;








Posted by freezn
익스플로러 외에 브라우져의 접근이 차단되어있거나 세션등으로 막은 경우 헤더조작이 까다로울 수 있습니다.

저 같은 경우 첫페이지에서 세션에 어떤 값을 넣어 첫페이지를 접근한 후 접속한 것이 아닌 사용자를 차단하는 사이트에서 소스를 얻을 필요가 있었는데요.

빨리 테스트해봐야해서 C#으로 웹브라우져 컴포넌트를 동원해서 작업하는 등 별 삽질을 다 했었습니다.

그.런.데

PHP에서 COM을 이용할 수 있는 함수가 있음을 알고 좌절했습니다. OTL

간단히 함수로 정리했습니다.
자... 보시죠(...)


예제 :
function getHTMLSrc( $url ) {
    // alloc COM (IE)
    $ie = new COM("InternetExplorer.Application");
    $ie->Visible = false;

    $ie->Navigate($url);
    while($ie->readyState!=4); // Loading Complete 확인
   
    $srcHTML = $ie->Document->documentElement->outerHTML;

    // free object
    $ie->Quit();
    unset($ie);

    return $srcHTML;
}


필요사항은

PHP5 이상 Windows version.
.Net 컴포넌트는 PHP5 와 .Net runtime.

뭐 결국 윈도우에 PHP5를 깔고 닷넷컴포넌트는 닷넷프레임워크만 깔아주면 된다는 거죠.

VB나 C#에서 사용하는 것이나 진배없는 속성들에 심하게 당황했습니다. PHP개발자들 대단하네요 -_-;;

COM클래스를 사용하게 되면...
MS Word, MS Excel, mdb 을 비롯한 상용 COM등 COM으로 만들어진 대부분의 처리가 가능한 것 같습니다 OTL

----------------------

예전에 써놨던 포스팅을 이사하면서 실수로 날렸었는데 "체리필터"님의 블로그에서 발견하고 역수입 -_-;;

다만 경험상 저렇게 ie object를 가져다 쓰고 해제해버리면 apache를 restart 시킬때까지 다시 살아나질 않았었다.
해서 최대한 해제하지 않고 한번 생성해서 우려먹었던 기억이...
Posted by freezn
작은 프로젝트에서 Windows + Apache + FirebirdSQL + PHP를 사용할 일이 있었습니다.
이 내용은 그 때 정리한 것입니다.

다들 아시겠지만 FirebirdSQL은 Borland Interbase 6.x대에서 오픈소스화 된 프로젝트로 무료로 사용가능하며 아주 작고 강력한 DBMS입니다.
이러한 특성때문에 많은 프로그램에서 자신들의 프로그램에 포함시켜 설치를 제공하는 곳이 많으며 Interbase와는 많은 호환이되어 PHP에서도 Interbase용 함수를 사용합니다.

--------------------------------------------------------------------
- Apache1.3 + FireBird 1.5 + PHP4.3 설치 과정

1. 버전
. Apache 1.3.33 - http://httpd.apache.org
. PHP 4.3.10 - http://php.net
. Firebird 1.4.2.4731 - http://firebirdsql.org



2. 설치파일들
. apache_1.3.33-win32-x86-no_src.exe
. php-4.3.10-Win32.zip
. Firebird-1.5.2.4731-Win32.exe


Apache와 Firebird는 설치, php는 적당한 경로에 압축을 풀어주세요.

3. httpd.conf 파일 설정
= httpd.conf에 다음과 같은 내용을 추가한다.

############################################################################
# Config for PHP4 on Apache 1.3.33
############################################################################
# 주의1. 아파치 설정에서 경로는 대신 /을 사용할 것.
# 주의2. 경로는 자신의 경로로 바꿀 것
AddType application/x-httpd-php .php
# For PHP 4
LoadModule php4_module "C:/PHP/sapi/php4apache.dll"
# specify the directory where php.ini is
SetEnv PHPRC "C:/PHP"
############################################################################

= httpd.conf 에서 DirectoryIndex 을 찾아 index.html 뒤에 index.php 를 추가한다.



4. PHP 설정
= PHP디렉토리의 php4ts.dll 파일을 windows 디렉토리로 복사
= PHP디렉토리의 php.ini-dist 파일을 php.ini 파일로 이름을 변경하여 window 디렉토리로 복사
= Interbase 의 사용을 위해 PHPdlls 에 있는 gds32.dll 을 windows의 system32 에 복사 (이미 존재할 시 덮어씌울 필요는 없음, 버전이 새로운 것이 높다면 덮어씌우면 됨)


= php.ini 에서 수정할 사항

; extension_dir = "C:PHPextensions"의 주석 제거
; (만약 extension_dir 의 경로가 다르다면 맞는 경로로 설정)
; extension=php_interbase.dll ;주석 제거
; magic_quotes_sybase 을 On으로


= php.ini 에서 추가할 사항

; 만약 이미 존재한다면 옵션만 수정할 것
[InterBase]
ibase.allow_persistent PHP_INI_SYSTEM
ibase.max_persistent PHP_INI_SYSTEM
ibase.max_links PHP_INI_SYSTEM
ibase.default_db PHP_INI_SYSTEM
ibase.default_user PHP_INI_ALL
ibase.default_password PHP_INI_ALL
ibase.default_charset PHP_INI_ALL
ibase.timestampformat PHP_INI_ALL
ibase.dateformat PHP_INI_ALL
ibase.timeformat PHP_INI_ALL




--------------------------------------------------------------------
- 설정 확인.
htdocs 에 php 파일을 하나 만들고 phpinfo(); 함수를 넣어봅니다.
웹으로 접속해봅시다.

보라색표에 PHP로고와 PHP Version 4.3.10 같은 문구가 나타났나요?
이제 ctrl+f로 interbase를 검색해봅시다.
관련 항목들이 나오며 Interbase Support enabled 로 나오나요?

그렇다면 설정이 제대로 된 것 입니다.^^



--------------------------------------------------------------------


설정 내용들의 간단한 설명

1. httpd.conf 의 설정에서.

다들 아시겠지만 httpd.conf는 아파치웹서버의 설정파일이다.
PHP 스크립트를 사용하기위해 아파치를 많이들 이용하며,

Windows상에서의 Apache+PHP연동에 대한 자료를 찾아보면 php.exe를 이용하는 방법이 많이 나와있다.
이런 팁들에서 특이한건 PHP모듈을 로딩해놓고도 php.exe를 이용한다는 것이다.
(이런 내용의 설정이다. Action application/x-httpd-php "/php/php.exe")

설치문서를 찾아보면 보안문제를 비롯한 여러문제로 인해 php.exe를 이용하는 방법은 권장하고 있지 않으며, php-apache 모듈의 이용을 권장하고 있다.

정확하지 않은 카더라통신 수준의 기억에 의하면 Windows 9X대 에서는 php.exe를 이용하는 수밖에 없기 때문에 그와같은 설정을 했던 것 같다.


2. PHP설정단계에서.
php4ts.dll 의 역할은 정확하게 기억나지 않는다. -_-;

php.ini 는 다들 아시겠지만 php의 설정파일이다. 나중에 메모리 제한등을 여기서 해결할 수 있다.

gds32.dll 은 GD라이브러리가 아닌 Interbase 연결을 위한 라이브러리이다. (에러가 나더라도 GD관련 에러로 착각하지 말자.)

3. php.ini수정에서.
magic_quotes_sybase 을 On으로 바꾸는 것은 Interbase/Firebird 관련 함수를 사용하기위해서 이렇게 하라고 http://kr2.php.net/ibase 에 나와있다. (왠지는 모른다.)

extension=php_interbase.dll 의 주석해제는 Interbase/Firebird 관련 함수가 들어있는 라이브러리 모듈을 활성화 시키는 것이다.
만약 이 라인을 그대로 주석인채 서비스를 연결해보면 관련 함수가 연결단부터 없는 함수라는 메세지를 보여줄 것이다.

--------------------------------------------------------------------

발견된 문제 #1
FirebirdSQL 을 Zip Binary(파일명 Firebird-1.5.2.4731_win32.zip) 으로 설치하였을 경우 Undefined service gds_db/tcp 라는 요상한메세지가 나오며 DB연결에 실패한다.
물론 설정 확인에서도 정상이었다.
- 해결책
FirebirdSQL을 Install 버전으로 설치한 후 다시 Uninstall 하고 FirebirdSQL을 다시 설정하면 정상적으로 된다. 이유는 아직 파악하지 못하였다.
아마 서비스등록과 레지스트리 등록외에도 무언가 필요한게 남는 것 같지만 좀더 알아봐야할 것 같다.

...윈도우즈system32driversetcservices 라는 파일이 있다.
이 파일에 gds_db 3050/tcp 식의 3050 tcp포트를 정의한 라인이 있는지 확인해보자. listening 포트를 정의하는 이 파일인 이것에 굳이 추가하지 않아도 되지만 좀더 확연한 처리를 위해 등록하곤 한다.

이것을 추가하는 것으로 해결이되었다.
특이한 것은 인스톨 버전에서는 이러한 내용이 없는 것으로 보아 다른 방법을 사용하는 것 같으며, 마지막
(뉴라인or 엔터) 를 잊지 말자.
Posted by freezn