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
TAG Linux, php

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
TAG MATLAB, php
익스플로러 외에 브라우져의 접근이 차단되어있거나 세션등으로 막은 경우 헤더조작이 까다로울 수 있습니다.

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

빨리 테스트해봐야해서 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
TAG COM, IE, php
작은 프로젝트에서 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