'팁&테크/PHP'에 해당되는 글 22건

  1. 2011.12.02 PHP 관련(메모)
  2. 2011.09.29 ip 필터링 클래스
  3. 2011.07.13 PHP 암호화 관련 개념 정리
  4. 2011.07.13 phpize (pdo_mysql 설치)
  5. 2011.05.19 PHP 코드를 최적화하는 40가지 팁
  6. 2011.05.18 PHP 코딩 규칙 v1
  7. 2011.05.09 PDO 예제
  8. 2010.05.20 php 이메일, ip 체크하는 정규식 함수
  9. 2009.11.17 hex2bin() 함수
  10. 2009.03.02 utf-8 로 이전하기
2011. 12. 2. 11:39

PHP 관련(메모)

1. 쉘로 백그라운드 실행
system('ls -al > /dev/null &');
출력을 null로 돌리고 백그라운드로 실행 
2011. 9. 29. 14:08

ip 필터링 클래스

<?php 
class IPFilter 

    private static 
$_IP_TYPE_SINGLE 'single'
    private static 
$_IP_TYPE_WILDCARD 'wildcard'
    private static 
$_IP_TYPE_MASK 'mask'
    private static 
$_IP_TYPE_SECTION 'section'
    private 
$_allowed_ips = array(); 

    public function 
__construct($allowed_ips
    { 
        
$this -> _allowed_ips $allowed_ips
    } 

    public function 
check($ip$allowed_ips null
    { 
        
$allowed_ips $allowed_ips $allowed_ips $this->_allowed_ips

        foreach(
$allowed_ips as $allowed_ip
        { 
            
$type $this -> _judge_ip_type($allowed_ip); 
            
$sub_rst call_user_func(array($this,'_sub_checker_' $type), $allowed_ip$ip); 

            if (
$sub_rst
            { 
                return 
true
            } 
        } 

        return 
false
    } 

    private function 
_judge_ip_type($ip
    { 
        if (
strpos($ip'*')) 
        { 
            return 
self :: $_IP_TYPE_WILDCARD
        } 

        if (
strpos($ip'/')) 
        { 
            return 
self :: $_IP_TYPE_MASK
        } 

        if (
strpos($ip'-')) 
        { 
            return 
self :: $_IP_TYPE_SECTION
        } 

        if (
ip2long($ip)) 
        { 
            return 
self :: $_IP_TYPE_SINGLE
        } 

        return 
false
    } 

    private function 
_sub_checker_single($allowed_ip$ip
    { 
        return (
ip2long($allowed_ip) == ip2long($ip)); 
    } 

    private function 
_sub_checker_wildcard($allowed_ip$ip
    { 
        
$allowed_ip_arr explode('.'$allowed_ip); 
        
$ip_arr explode('.'$ip); 
        for(
$i 0;$i count($allowed_ip_arr);$i++) 
        { 
            if (
$allowed_ip_arr[$i] == '*'
            { 
                return 
true
            } 
            else 
            { 
                if (
false == ($allowed_ip_arr[$i] == $ip_arr[$i])) 
                { 
                    return 
false
                } 
            } 
        } 
    } 

    private function 
_sub_checker_mask($allowed_ip$ip
    { 
        list(
$allowed_ip_ip$allowed_ip_mask) = explode('/'$allowed_ip); 
        
$begin = (ip2long($allowed_ip_ip) &ip2long($allowed_ip_mask)) + 1
        
$end = (ip2long($allowed_ip_ip) | (~ip2long($allowed_ip_mask))) + 1
        
$ip ip2long($ip); 
        return (
$ip >= $begin && $ip <= $end); 
    } 

    private function 
_sub_checker_section($allowed_ip$ip
    { 
        list(
$begin$end) = explode('-'$allowed_ip); 
        
$begin ip2long($begin); 
        
$end ip2long($end); 
        
$ip ip2long($ip); 
        return (
$ip >= $begin && $ip <= $end); 
    } 

?> 

useage: 
<?php 
$filter 
= new IPFilter
    array( 
        
'127.0.0.1'
        
'172.0.0.*'
        
'173.0.*.*'
        
'126.1.0.0/255.255.0.0'
        
'125.0.0.1-125.0.0.9'
)); 
$filter -> check('126.1.0.2'); 
?>

출처 : http://kr.php.net/manual/en/function.ip2long.php 
2011. 7. 13. 14:58

PHP 암호화 관련 개념 정리

암호화

암호화(Cryptography)는 일종의 예술이다. 암호문은 몇 개의 단어를 바꾼 로마의 궤변에서부터 요즘에 사용하는 공개 키와 개인 키(public and private key) 메커리즘에 이르기까지 여러 세기에 걸쳐 사용되었다. 암호화의 목적은 지정된 사람 이외에는 누구도 볼 수 없는 암호문을 만드는 것이다.

이제 몇 페이지에 요즈음 인터넷에서 사용되는 몇 가지 암호화 방식과 동작 원리, 사용대상 등에 대해 살펴보도록 하자.

단방향 암호화

이 방식은 원문을 해독할 수 없도록 암호화하는 과정이다. 언뜻 들으면 사용할 수 없는 방법 같지만 실제 컴퓨터 분야에서는 많이 사용되는 방법이다.

단방향 암호화에 사용되는 알고리즘은 자주 해싱 알고리즘(hashing algorithms)이라고 부른다. 이것은 원문을 이용해 고유한 문자열을 만들어 내는 과정이다. PHP에서 가장 널리 사용되는 해싱 알고리즘은 MD5 알고리즘이다. 이 알고리즘의 실제 동작 방식에 대해서는 자세히 설명하지 않지만 이 방식은 어떤 문자열을 받아서 128비트로 된 고유한 값(fingerprint)을 만들어 내는 것이다.

현재 이 고유한 값을 이용해 거꾸로 원래의 문자열을 알아내는 방법은 불가능하다고 생각된다. 또한 두 가지 문자열에서 생성된 값이 서로 같게 될 확률도 거의 없다. 이 시스템을 완전히 난공불락으로 생각할 수도 있지만, 예상 가능한 문자열을 이용해 무작위로 입력해 그 결과를 비교하는 방법에는 취약하다. 이 공격에 필요한 시간은 해시 데이터의 복잡성에 따라 다르지만 짧은 암호 해독에 걸리는 시간은 그리 길지 않다.

암호가 안전하기만 하다면 MD5 알고리즘은 암호를 암호화하는 좋은 방법이다. 그 이유는 원래의 암호를 다시 해독할 수는 없지만 로그인 시에 사용자가 입력한 암호를 해시로 만들어 비교할 수는 있기 때문이다.

일반 텍스트로 저장된 암호는 보안상 매우 위험하면 MD5 알고리즘을 이용해 변환된 값을 저장해야 한다. 사용자가 로그인해 자신의 암호를 입력하면 이것은 MD5 암호화 과정을 거치게 된다. 만일 이 해시 값이 이미 저장되어 있던 것과 같으며, 두 개의 암호는 서로 같다고 판단된다.

간단한 암호를 사용하는 것은 브루트 포스 공격(brute force attack)의 대상이 되기 때문에 매우 위험하다는 것을 명심하기 바란다. 안전한 암호를 선택하는 방법은 이 장의 끝에 나와 있는 참고 자료를 이용하면 된다.

PHP의 md5() 함수는 다음과 같이 문자열을 입력받아 고유한 값을 만들어 낸다: 

<?php
$fingerprint = md5($password);
?>

Important 

MD5 알고리즘은 다양한 용도로 사용된다. 그 중하나는 파일이 수정되었는지를 확인할 때 사용된다는 것이다. 파일의 MD5 해시를 저장해 두면 이 파일이 변경되었는지를 금방 확인할 수 있다. 


CRC32 함수도 비슷한 기능을 한다. CRC32 함수는 128비트가 아닌 32비트의 고유 값을 생성하기 때문에 암호에는 적당하지 않다. 따라서 두 개의 입력 값이 같은 결과를 나타탤 확률이 더 높다.

MD5와 CRC32 함수 이외에, PHP는 mhash 라이브러리를 제공한다. 이 추가적인 알고리즘는 mhash() 함수를 이용한다. 이 함수는 두 개 또는 세 개의 인자를 사용한다. 첫 번째 인자는 알고리즘을 나타내는 상수, 두 번재 인자는 해시로 만들 문자열, 세 번째 인자는 해싱 알고리즘에서 사용되는 키(key)이다. 다음은 MD5 알고리즘과 mhash()를 이용한 해싱의 예이다: 

<?php
$passphrase = "this is my secret passphrase";
echo("My passpharse hashed using md5 is: ");
echo(mhash(MASH_MD5, $passphrase));
?>

mhash를 지원하는 주요 알고리즘은 다음과 같다. 좀더 자세한 정보는 http://mhash.sourceforce.net/ 을 참고하면 된다.

알고리즘 
특징 

CRC32 
이 알고리즘은 주로 데이터 전송 시에 체크섬(checksums)을 위해 사용된다. mhash는 이 알고리즘을 위해 두 가지를 제공하는데, MHASH_CRC32는 주로 이더넷 통신에서 사용되면 MHASH_CRC32는 ZIP 프로그램에서 사용된다. 

MD5 
md5() 함수의 알고리즘이다. 상수 MHASH_MD5를 사용한다. 

MD4 
MD4는 MD5와 비슷하지만 보안성이 떨어진다. MD5로 대체되었기 때문에 MD4를 사용하지 않는다. MHASH_MD4 상수를 사용한다. 

SHA1 
이 알고리즘은 NIST의 디지털 서명 표준을 사용된다. 상수 MHASG_SHA1을 사용한다. 

HAVAL 
MD5의 변형 판으로 다양한 길이의 결과를 갖는다. mhash에서는 MHASH_HAVAL256, MHASH_MAVAL192, MHASH_HAVAL160, MHASH_HAVAL128 등을 사용한다. 

RIPEMD160 
MD4, MD5, RIPEMD를 대체하기 위해 설계된 160비트 알고리즘이다. 그러나 여전히 MD5가 많이 사용되고 있다. 상수 MHASH_RIPEMD160을 이용한다. 

TIGER 
TIGER은 매우 빠른 해싱 기능을 위해 설계되었다. 원래 64비트 컴퓨터에서 사용하려고 설계되었지만 다른 컴퓨터에서 그다지 느리지는 않다. 상수 MHASH_TIGER192, MHASH_TIGER160, MHASH_TIGER128을 사용한다. 

GOST 
러시아의 디지털 서명 표준으로 256비트를 지원한다. 상수 MHASH_GOST를 사용한다. 


대칭형 암호화(Symmetric Encryption)

키(key)를 이용해 문자열을 암호화하는 방버이다. 전송자와 수신자가 알고 있는 키를 이용해 동일한 알고리즘에서 문자열을 암호화/복호화 한다. 2차 세계 대전 중에 암호화 기계(enigma machine)에 사용된 방식이다.

이 암호화 방식은 많은 약점과 문제점이 있다. 그 중 하나는 전송자와 수신자가 키를 알고있는 유일한 사람들인지를 확인하는 것이다. 만일 누군가 타인이 키를 얻어 암호화 된 메시지를 가로챈다면 이 메시지를 해석하는 것은 매우 간단한 일이다. 일반적으로 생각해서 만일 키를 안전하게 보관할 수만 있다면 이 방식은 매우 안전하다. PHP에서는 mcrypt 라이브러리를 이용해서 다양한 알고리즘을 이용하는 호스트에 접근할 수 있다.

mcrypt에서 사용되는 일반적인 암호화 방식은 다음과 같다. 보다 자세한 정보는 http://mcrypt.hellug.gr/mcrypt/mcrypt.html을 참고했다.

알고리즘 
특징 

DES 
전통적인 DES 알고리즘으로 키의 길이가 작아 비교적 보안에 취약하다. 상수 MCRYPT_DES를 사용한다. 

3DES/Triple DES 
DES의 변형 판이다. 유효 키 길이는 112비트이다. 상수 MCRYPT_3DES를 사용한다. 

CAST-128 
캐나다에서 설계된 알고리즘으로 128비트 키와 64비트 블럭을 가진다. 상수 MCRYPT_CAST_128을 사용한다. 

CAST-256 
CAST-128의 확장 판으로 알고리즘으로 256비트 키와 128비트 블럭을 가진다. 상수 MCRYPT_CAST_256을 사용한다. 

XTEA 
128비트 키와 64비트 브럭을 가진다. 상수 MCRYPT_XTEA를 사용한다. 

3-WAY 
96비트 키와 블럭을 가진다. 상수 MCRYPT_THREEWAY를 사용한다. 

SKIPJACK 
미국 NSA에서 조건부 암호화 표준으로 설계한 알고리즘이지만 표준화되지 못했다. mcryp에서 추가 라이브러리를 이용해 접근할 수 있으며 80비트 키를 가진다. 상수 MCRYPT_SKIPJACK를 사용한다. 

BLOWFISH 
DES를 개선한 알고리즘으로 최대 448비트 길이의 키를 사용할 수 있다. 상수 MCRYPT_BLOWFISH를 사용한다. 

TWOFISH 
보안성이 높고 융통성이 있다. 128, 192, 256비트 키를 지원한다. 상수 MCRYPT_TWOFISH를 사용한다. 

LOKI97 
128, 192, 256비트 길이의 키를 이용한다. 상수 MCRYPT_LOKI97를 사용한다. 

RC2 
블럭 크기를 64비트이며 키는 8에서 1024비트이다. 오래된 알고리즘으로 16비트 컴퓨터에 적당하다. 상수 MCRYPT_RC2를 사용한다. 

ARCFOUR/RC4 
RC4는 RSADSL의 상표이므로 mcrypt는 RC4 알고리즘을 지원하지 않지만 ARCFOUR와 호환된다. 스트림 기반의 암호문과 최대 2048 비트 키를 지원한다. 상수 MCRYPT_ARCFOUR를 사용한다. 

RIJNDAEL 
가변적인 길의 블럭 암호문과 키를 가진다. 상수 MCRYPT_RIJNDAEL_128, MCRYPT_RIJNDAEL_192, MCRYPT_RIJNDAEL_256을 사용한다. 

SERPENT 
128비트 블럭 암호문으로 DES보다 빠르다. 상수 MCRYPT_SERPENT를 사용한다. 

IDEA 
64비트 블럭과 128비트 키를 사용한다. 상수 MCRYPT_IDEA를 사용한다. 

ENIGMA/CRYPT 
하나의 원통을 가진 암호화 기계를 기반으로 해서 보안성이 낮다. 상수 MCRYPT_CRYPT를 사용한다. 

GOST 
256비트 키와 64비트 블럭을 가진다. 상수 MCRYPT_GOST를 사용한다. 

SAFER 
64비트, 128비트 키를 지원하는 빠르고 안전한 알고리즘이다. 상수 MCRYPT_SAFER64, MCRYPT_SAFER128을 사용한다. 

SAFER+ 
SAFER 알고리즘의 확장판으로 128, 196, 256비트 키를 지원한다. 상수 MCRYPT_SAFERPLUS를 사용한다. 


예를 들어, 3DES 알고리즘을 사용하려면 다음과 같이 키를 이용해 문자열을 암호화한다: 

<?php
$key = "This is our secret key";
$string = "This is ths string that we want to encrypt"; // 문자열 암호화
$encrypted_message = mcrypt_ech(MCRYPT_3DES, $key, $string, MCRYPT_ENCRYPT);
?>

이 메시지를 해독하려면 $encrypted_message를 문자열로 해서 MCRYPT_DECRYPT 상수를 이용하면 된다. 위의 코드를 mcrypt 2.2.x와 2.4.x에서 동작한다. mcrypt 2.4.x 함수가 좀더 더 유연한 기능을 제공하므로 이 함수를 사용하기를 권한다.

비대칭 암호화

비대칭 암호화(Asymmetric encryption)는 몇 년 전부터 일반인들이 사용할 수 있게 되었다. 이 방식은 상자와 자물쇠로 생각하면 이해가 쉽다. 예를 들어, 제인이 앨리스에게 보내는 비밀 메시지를 가지고 있다면 앨리스는 제인에게 열려있는 자물쇠를 보낼 수 있다. 제인은 자신의 메시지를 상자에 넣고 앨리스가 보내준 자물쇠를 이용해 상자를 잠근다.

이제 상자를 열과 메시지를 읽을 수 있는 유일한 사람은 앨리스인데 열쇠는 앨리스만이 가지고 있기 때문이다.

비대칭 암호화를 이용할 때는 자신의 공개 키(pubic key)를 보내야 한다. 이 공개 키를 열려져 있는 자물쇠라고 생각해보자. 누구든지 이 열려진 자물쇠를 이용해 여러분에게 비밀 메시지를 보낼 수 있고 개인 키(private key)는 여러분이 가지고 있으므로 이 자물쇠를 열수 있는 유일한 사람이 된다.

이 시스템은 인터넷에서 흔히 사용된다. 만일 인터넷에서 물건을 구입하거나 PGP(Pretty Good Privacy)를 사용한다면 이 시스템을 이용하는 것이다.

PHP는 OpenSSL을 이용해 이 시스템을 지원한다. 또한 OpenSSL은 CURL을 이용해 리모트 서버에 SSL(Secure Socket Layer)로 연결할 수 있다. 사용되는 세부 알고리즘은 상당히 복잡하다. 이 장의 마지막에 있는 참고 정버를 이용하면 많은 정보를 얻을 수 있다. 비대칭 암화는 다른 것보다 좀더 안전하다.

아래는 지원하는 암호화 방식의 종류
MCRYPT_3DES
MCRYPT_ARCFOUR_IV (libmcrypt > 2.4.x only)
MCRYPT_ARCFOUR (libmcrypt > 2.4.x only)
MCRYPT_BLOWFISH
MCRYPT_CAST_128
MCRYPT_CAST_256
MCRYPT_CRYPT
MCRYPT_DES
MCRYPT_DES_COMPAT (libmcrypt 2.2.x only)
MCRYPT_ENIGMA (libmcrypt > 2.4.x only, alias for MCRYPT_CRYPT)
MCRYPT_GOST
MCRYPT_IDEA (non-free)
MCRYPT_LOKI97 (libmcrypt > 2.4.x only)
MCRYPT_MARS (libmcrypt > 2.4.x only, non-free)
MCRYPT_PANAMA (libmcrypt > 2.4.x only)
MCRYPT_RIJNDAEL_128 (libmcrypt > 2.4.x only)
MCRYPT_RIJNDAEL_192 (libmcrypt > 2.4.x only)
MCRYPT_RIJNDAEL_256 (libmcrypt > 2.4.x only)
MCRYPT_RC2
MCRYPT_RC4 (libmcrypt 2.2.x only)
MCRYPT_RC6 (libmcrypt > 2.4.x only)
MCRYPT_RC6_128 (libmcrypt 2.2.x only)
MCRYPT_RC6_192 (libmcrypt 2.2.x only)
MCRYPT_RC6_256 (libmcrypt 2.2.x only)
MCRYPT_SAFER64
MCRYPT_SAFER128
MCRYPT_SAFERPLUS (libmcrypt > 2.4.x only)
MCRYPT_SERPENT (libmcrypt > 2.4.x only)
MCRYPT_SERPENT_128 (libmcrypt 2.2.x only)
MCRYPT_SERPENT_192 (libmcrypt 2.2.x only)
MCRYPT_SERPENT_256 (libmcrypt 2.2.x only)
MCRYPT_SKIPJACK (libmcrypt > 2.4.x only)
MCRYPT_TEAN (libmcrypt 2.2.x only)
MCRYPT_THREEWAY
MCRYPT_TRIPLEDES (libmcrypt > 2.4.x only)
MCRYPT_TWOFISH (for older mcrypt 2.x versions, or mcrypt > 2.4.x )
MCRYPT_TWOFISH128 (TWOFISHxxx are available in newer 2.x versions, but not in the 2.4.x versions)
MCRYPT_TWOFISH192
MCRYPT_TWOFISH256
MCRYPT_WAKE (libmcrypt > 2.4.x only)
MCRYPT_XTEA (libmcrypt > 2.4.x only)
 

여러곳에 퍼져있는 글이라 원작자는 알 수 없으나 많은 도움이 되었습니다.
원작자님 감사합니다. 
2011. 7. 13. 11:46

phpize (pdo_mysql 설치)

phpize는 php에서 extension 모듈을 올리는 데 필요한 유틸리티입니다.
phpize는 php-devel에 속한 패키지이며, 정말 유용합니다.
configure 관련 파일이 없을 경우 생성해줍니다.


우선 phpize가 있는 지 확인하고요~


--------------------------------------------------------
1. phpize가 있는지 확인 
--------------------------------------------------------
[root@ns1 22:04:05 ~]$ whereis phpize
phpize: /usr/bin/phpize

제 시스템 같은 경우는 /usr/bin/phpize에 존재합니다.(yum으로 php-devel 설치 시)
없으면, php-devel을 설치하시면 됩니다. 
소스 컴파일로 PHP를 설치하신 경우에는 설치디렉토리/bin 에 phpize파일이 존재합니다. 



--------------------------------------------------------
2. httpd가 DSO 지원되는 지 체킹 
--------------------------------------------------------
[root@ns1 22:05:15 ~]$ httpd -l
Compiled-in modules:
  http_core.c
  mod_so.c 


--------------------------------------------------------
3. extension 설치 
--------------------------------------------------------
* 테스트로 php에 기본 소스인 있는 pdo_mysql 설치

[root@ns1 22:17:24 ~/php-5.2.5/ext/pdo_user]$ phpize   // extension 컴파일 지정
Configuring for:
  PHP Api Version:   20020918
  Zend Module Api No:   20020429
  Zend Extension Api No:   20021010

[root@ns1 22:15:03 ~/php-5.2.5/ext/pdo_mysql]$ ./configure --with-php-config=/usr/local/php/bin/php-config --with-pdo-mysql=/usr/local/mysql

[root@ns1 22:15:03 ~/php-5.2.5/ext/pdo_mysql]$ make
[root@ns1 22:15:03 ~/php-5.2.5/ext/pdo_mysql]$ make install 
// make install 을 하면 어디에 so 파일이 생성되었다고 나옵니다.


// 각자 모듈 올리는 곳(php.ini의 extension_dir 부분 참조)에 복사해 넣으시면 됩니다.
[root@ns1 22:15:03 ~/php-5.2.5/ext/pdo_mysql]$ cp ../modules/pdo_user.so /usr/localphp/php/modules 


// extension 추가함
[root@ns1 22:15:03 ~]$ vi /usr/local/php/php.ini 
extension=pdo_user.so 


// 아파치 리스타트 하면 적용됨
// 위의 경로들은 소스 컴파일한 php의 경로입니다. rpm 이나 yum으로 설치했을 각 파일의 경로가 다르니 주의하세요.
2011. 5. 19. 15:36

PHP 코드를 최적화하는 40가지 팁

1. If a method can be static, declare it static. Speed improvement is by a factor of 4.
메쏘드가 static이 될 수 있다면 static으로 선언하라. 4배 빨라진다.

2. echo is faster than print.
echo가 print보다 빠르다.

3. Use echo’s multiple parameters instead of string concatenation.
문자열을 이어붙이지 말고, echo를 이용하여 여러 개의 파라미터를 적어라.

4. Set the maxvalue for your for-loops before and not in the loop.
for 루프을 위핸 최대값(탈출조건)을 루프 안에서가 아니고 루프 시작 이전에 지정하라.

5. Unset your variables to free memory, especially large arrays.
메모리를 해제하기 위해 변수를 unset하라. 특히 커다란 배열은 그래야 된다.

6. Avoid magic like __get, __set, __autoload
__get, __set, __autoload와 같은 마법을 피해라.

7. require_once() is expensive
require_once()는 비싸다.

8. Use full paths in includes and requires, less time spent on resolving the OS paths.
include와 require를 사용할 때, 경로를 찾는데 시간이 적게 걸리는 full path를 사용하라. 

9. If you need to find out the time when the script started executing, $_SERVER[’REQUEST_TIME’] is preferred to time()
스크립트가 언제 실행했는지 알고 싶으면 time()보다 $_SERVER['REQUEST_TIME']이 좋다.

10. See if you can use strncasecmp, strpbrk and stripos instead of regex
정규표현식보다는 가능하면 strncasecmp나 strpbrk, stripos를 사용하라.
* 역주
strncasecmp: 두 문자열의 앞쪽 일부가 대소문자 구분없이 일치하는지 확인할 때 사용
strpbrk: 문자 집합에 속한 특정 문자가 문자열에 나타나는지 확인할 때 사용
stripos: 대소문자 구분없이 특정 문자열이 다른 문자열에 포함되는지 확인할 때 사용

11. str_replace is faster than preg_replace, but strtr is faster than str_replace by a factor of 4
str_replace가 preg_replace보다 빠르지만, strtr은 str_replace보다 4배 빠르다.

12. If the function, such as string replacement function, accepts both arrays and single characters as arguments, and if your argument list is not too long, consider writing a few redundant replacement statements, passing one character at a time, instead of one line of code that accepts arrays as search and replace arguments.
만약 문자열 교체 같은 함수가 배열과 문자열을 인자로 받아들이면, 그리고 그 인자 리스트가 길지 않다면, 배열을 한 번에 받아들여서 처리하는 것 대신에 한 번에 문자열을 하나씩 넘겨서 처리하는 것을 고려해봐라. 

13. It’s better to use select statements than multi if, else if, statements.
여러 개의 if/else if 문장 대신에 select 문장을 사용하는 게 더 좋다. 

14. Error suppression with @ is very slow.
@를 이용한 에러 출력 방지는 매우 느리다.

15. Turn on apache’s mod_deflate
Apache의 mod_deflate를 켜라.
*역주
mod_deflate는 서버의 출력을 클라이언트에게 보내기 전에 압축하는 모듈임

16. Close your database connections when you’re done with them
DB를 다 사용했으면 연결을 닫아라.

17. $row[’id’] is 7 times faster than $row[id]
$row['id']가 $row[id]보다 7배 빠르다.

18. Error messages are expensive
에러 메시지는 비싸다.

19. Do not use functions inside of for loop, such as for ($x=0; $x < count($array); $x) The count() function gets called each time.
for 루프의 표현식 안에서 함수를 사용하지 마라.
for ($x = 0; $x < count($array); $x)에서 count() 함수가 매번 호출된다.

20. Incrementing a local variable in a method is the fastest. Nearly the same as calling a local variable in a function.
메쏘드 안에서 지역 변수를 증가시키는 것이 거의 함수 안에서 지역 변수를 호출(증가?)하는 것만큼 빠르다.

21. Incrementing a global variable is 2 times slow than a local var.
전역 변수를 증가시키는 것이 지역 변수를 증가시키는 것보다 2배 느리다.

22. Incrementing an object property (eg. $this->prop++) is 3 times slower than a local variable.
객체의 멤버변수를 증가시키는 것이 지역 변수를 증가시키는 것보다 3배 느리다.

23. Incrementing an undefined local variable is 9-10 times slower than a pre-initialized one.
값이 지정되지 않은 지역 변수를 증가시키는 것이 미리 초기화된 변수를 증가시키는 것보다 9~10배 느리다.

24. Just declaring a global variable without using it in a function also slows things down (by about the same amount as incrementing a local var). PHP probably does a check to see if the global exists.
전역 변수를 함수 안에서 사용하지 않으면서 그저 선언하기만 해도 (지역 변수를 증가시키는 것만큼) 느려진다. PHP는 아마 전역 변수가 존재하는지 알기 위해 검사를 하는 것 같다.

25. Method invocation appears to be independent of the number of methods defined in the class because I added 10 more methods to the test class (before and after the test method) with no change in performance.
메쏘드 호출은 클래스 안에서 정의된 메쏘드의 갯수에 독립적인 듯 하다. 왜냐하면 10개의 메쏘드를 테스트 클래스에 추가해봤으나 성능에 변화가 없었기 때문이다.

26. Methods in derived classes run faster than ones defined in the base class.
파생된 클래스의 메쏘드가 베이스 클래스에서 정의된 것보다 더 빠르게 동작한다.

27. A function call with one parameter and an empty function body takes about the same time as doing 7-8 $localvar++ operations. A similar method call is of course about 15 $localvar++ operations.
한 개의 매개변수를 가지고 함수를 호출하고 함수 바디가 비어있다면(함수 내부에서 아무것도 실행하지 않는다면) 그것은 7~8개의 지역변수를 증가시키는 것과 똑같은 시간을 차지한다. 비슷한 메쏘드 호출은 마찬가지로 15개의 지역변수를 증가시키는 연산쯤 된다.

28. Surrounding your string by ‘ instead of ” will make things interpret a little faster since php looks for variables inside “…” but not inside ‘…’. Of course you can only do this when you don’t need to have variables in the string.
문자열을 이중 따옴표 대신에 단일 따옴표로 둘러싸는 것은 좀 더 빠르게 해석되도록 한다. 왜냐하면 PHP가 이중 따옴표 안의 변수를 찾아보지만 단일 따옴표 안에서는 변수를 찾지 않기 때문이다. 물론 문자열 안에서 변수를 가질 필요가 없을 때만 이렇게 사용할 수 있다.

29. When echoing strings it’s faster to separate them by comma instead of dot. Note: This only works with echo, which is a function that can take several strings as arguments.
문자열을 echo할 때 마침표 대신에 쉼표로 분리하는 것이 더 빠르다.
주의: 이것은 여러 문자열을 인자로 받아들이는 함수인 echo로만 작동한다. 

30. A PHP script will be served at least 2-10 times slower than a static HTML page by Apache. Try to use more static HTML pages and fewer scripts.
Apache에 의해 PHP 스크립트는 정적 HTML 페이지보다 최소 2에서 10배 느리게 서비스된다. 더 많은 정적 HTML 페이지와 더 적은 스크립트를 사용하려고 노력하라.

31. Your PHP scripts are recompiled every time unless the scripts are cached. Install a PHP caching product to typically increase performance by 25-100% by removing compile times.
PHP 스크립트는 캐시되지 않으면 매번 재 컴파일된다. 컴파일 시간을 제거함으로써 25~100%만큼의 성능을 증가시키기 위해 PHP 캐싱 도구를 설치하라.

32. Cache as much as possible. Use memcached - memcached is a high-performance memory object caching system intended to speed up dynamic web applications by alleviating database load. OP code caches are useful so that your script does not have to be compiled on every request
가능한 한 많이 캐시하라. memcached를 사용하라. memcached는 고성능 메모리 객체 캐싱 시스템이다.

33. When working with strings and you need to check that the string is either of a certain length you’d understandably would want to use the strlen() function. This function is pretty quick since it’s operation does not perform any calculation but merely return the already known length of a string available in the zval structure (internal C struct used to store variables in PHP). However because strlen() is a function it is still somewhat slow because the function call requires several operations such as lowercase & hashtable lookup followed by the execution of said function. In some instance you can improve the speed of your code by using an isset() trick.
문자열을 가지고 작업하며 문자열이 특정 길이인지 확인할 필요가 있을 때, strlen() 함수를 쓸 것이다. 이 함수는 계산없이 zval 구조체에서 사용할 수 있는 이미 알려진 문자열 길이를 반환하기 때문에 매우 빠르다. 그러나 strlen()이 함수이기 때문에 여전히 조금 느리다. 왜냐하면 함수 호출은 언급된 함수의 실행 뒤에 lowercase와 hashtable lookup같은 여러 개의 연산을 호출하기 때문이다. 어떤 경우에는 isset() 트릭을 이용하여 코드의 스피드를 증가시킬 수도 있다.

Ex.
if (strlen($foo) < 5) { echo "Foo is too short"; }
vs.
if (!isset($foo{5})) { echo "Foo is too short"; }

Calling isset() happens to be faster then strlen() because unlike strlen(), isset() is a language construct and not a function meaning that it's execution does not require function lookups and lowercase. This means you have virtually no overhead on top of the actual code that determines the string's length.
isset()을 호출하는 것은 strlen()과는 달리 isset()이 언어 기본문법이고 함수가 아니기 때문에 함수 찾와 lowercase 작업을 필요로 하지 않으므로 strlen()보다 더 빠를 수도 있다. 이것은 가상적으로 문자열의 길이를 결정하는 실제 코드에 과부하가 없다는 것을 의미한다.

34. When incrementing or decrementing the value of the variable $i++ happens to be a tad slower then ++$i. This is something PHP specific and does not apply to other languages, so don't go modifying your C or Java code thinking it'll suddenly become faster, it won't. ++$i happens to be faster in PHP because instead of 4 opcodes used for $i++ you only need 3. Post incrementation actually causes in the creation of a temporary var that is then incremented. While pre-incrementation increases the original value directly. This is one of the optimization that opcode optimized like Zend's PHP optimizer. It is a still a good idea to keep in mind since not all opcode optimizers perform this optimization and there are plenty of ISPs and servers running without an opcode optimizer.
변수 $i의 값을 증가시키거나 감소키킬 때, $i++은 ++$i보다 조금 더 느릴 수 있다. 이것은 PHP의 특징이고 다른 언어에는 해당되지 않으니 좀 더 빨라질 것을 기대하면서 C나 Java 코드를 바꾸러 가지 마라. 안 빨라질 것이다. ++$i는 PHP에서 좀 더 빠른데 그것은 $i++에 4개의 opcode가 사용되는 대신에 3개만 필요하기 때문이다. 후증가는 사실 증가될 임시변수의 생성을 초래한다. 반면에 전증가는 원래 값을 직접 증가시킨다. 이것은 opcode가 Zend의 PHP optimizer처럼 최적화하는 최적화 기법의 하나이다. 모든 opcode optimizer들이 이 최적화를 수행하는 것은 아니고 많은 ISP와 server들이 opcode optimizer없이 수행되고 있기 때문에 명심하는 게 좋을 것이다.

35. Not everything has to be OOP, often it is too much overhead, each method and object call consumes a lot of memory.
모든 것이 OOP일 필요는 없다. 종종 그것은 너무 많은 과부하가 된다. 각각의 메쏘드와 객체 호출은 메모리를 많이 소비한다.

36. Do not implement every data structure as a class, arrays are useful, too
모든 데이터 구조를 클래스로 구현하지 마라. 배열도 유용하다.

37. Don't split methods too much, think, which code you will really re-use
메쏘드를 너무 많이 분리하지 마라. 어떤 코드를 정말 재사용할지 생각해봐라.

38. You can always split the code of a method later, when needed
항상 메쏘드의 코드를 나중에 필요할 때 분리할 수 있다.

39. Make use of the countless predefined functions
수많은 미리 정의된 함수를 활용해라.

40. If you have very time consuming functions in your code, consider writing them as C extensions
매우 시간을 소비하는 함수가 있다면, C 확장으로 작성하는 것을 고려해봐라.

41. Profile your code. A profiler shows you, which parts of your code consumes how many time. The Xdebug debugger already contains a profiler. Profiling shows you the bottlenecks in overview
당신의 코드를 프로파일해봐라. 프로파일러는 코드의 어떤 부분이 가장 많은 시간을 소비하는지 보여준다. Xdebug 디버거는 이미 프로파일러를 포함하고 있다. 프로파일링은 전체적인 병목을 보여준다.

42. mod_gzip which is available as an Apache module compresses your data on the fly and can reduce the data to transfer up to 80%
Apache 모듈로 사용가능한 mod_gzip은 실행 중에 데이터를 압축하여 전송할 데이터를 80%까지 줄일 수 있다.

43. Excellent Article about optimizing php by John Lim
John Lim의 PHP를 최적화하는 것에 관한 뛰어난 글  

출처 : 
http://www.cyworld.com/be2u/2499807
2011. 5. 18. 10:58

PHP 코딩 규칙 v1

개인적으로 사용하는 코딩규칙임
 

일반

PHP태그는 <?php ?> 형태로 한다. short open tag 허용 안함. (<? ?>)
<?php echo $var ?> 허용
<?=$var?> 불가
코드의 마지막이 PHP로 이루어져있을 경우 ?> 는 반드시 생략.

배열, 함수인자등 , 다음에는 반드시 공백을 넣을것.
array(1, 2, 3, 4);
function($a, $b, $c);

탭은 공백 4개 사용, 탭문자 사용 불허

파일인코딩

파일 저장 인코딩 방식은 기본 UTF-8 (BOM 없음)

클래스

Camel Case 방식 각단어의 첫글자는 대문자
예) class MyOwnClass

선언
class MyOwnClass {
}

메소드

Camel Case 방식 첫단어 소문자, 접근제한자(public, protected, private) 사용(PHP5)
예) public function myOwnMethod()

선언
public function myOwnMethod()  {
}

함수

C형태 함수 선언, 기존 함수체계와 유사성 유지
예) function my_function() 

선언
function my_function() {
}

상수명

대문자와 _ 만 사용
예) MY_CONSTANT

TRUE, FALSE, NULL 대문자 사용

변수명

소문자와 _ , 숫자 사용, GET Query시 URL을 소문자로 통일하기 위함
예) $my_vars

가변변수 사용시 {}를 사용, $$ 사용금지
${$var1} = 'value';

문자열

문자열 내의 변수 사용은 아래 형식만 허용
$var = "내 이름은 {$name}입니다.";
$var = '내 이름은'.$name.'입니다.';

DB

테이블 및 필드명은 소문자, _, 숫자를 사용
- 오라클,MSSQL 및 몇몇 DB 라이브러리의 경우 일괄적으로 대/소문자만으로 변환되어 사용되어
  혼란이 야기됨
예) ORACLE은 기본적으로 대문자를 사용하므로 Camel Case로 만들경우 구분이 어려움
예) MSSQL은 대소문자 구분하지 않으나 PHP에서는 배열index의 대소문자를 구분하므로 혼란스러움

DB예약어는 대문자, 필드/테이블/뷰등 사용자가 정의한 object는 소문자를 사용
짧은 쿼리
$query = "SELECT field FROM table WHERE field=1";
긴쿼리
$query = "SELECT field, field, field "
               ."FROM table "
               ."WHERE field = 1";

배열

배열 값후에 , 뒤에는 반드시 공백을 포함하도록 함
 
$ar = array(1, 2, 3, 4);
배열값을 여러줄로 나눌경우 ,는 값 뒤쪽에 위치하도록 함
$ar = array(
          1,
          2,
);

배열선언시 아래와 같은 형태로만 선언할 것
한줄
$ar = array(1, 2, 3, 4);

여러줄
$ar = array(
          1,
          2,
);

$ar = array(
          'key1' => 'value1',
          'key2' => 'value2'
);

명령구문 중간에서 여러줄 배열 선언시 
$aa = implode('-',array(
                                     1, 2, 3,
                                     4, 5, 6, 3
                                     ));
$aa = implode('-',array(
                                     'key1' => 'value1',
                                     'key2' => 'value2'
                                     ));

FOR문 사용

반복 조건문에서 함수를 사용할 경우 반드시 변수 초기화 할때 함수의 값을 저장해서 사용
for($i=0, $cnt=count($row); $i<$cnt; $i++) {
}

블럭

모든 블럭은 명령어 바로 다음에 위치하도록 함
if() {
}

while() {
}

IF ELSE

if문에 else가 필요할 경우 블럭 다음줄에서 시작함(블럭 인식이 편함)
if(조건) {

else {
}

elseif 는 사용하지 말고 else if를 사용함(몇몇 언어에서 elseif 지원안함 - javascript)
if(조건) {
}
else if(조건) {
}
else {
}

Switch

탭으로 들여쓰기해야 하며 default 구문은 반드시 포함되어야 함
switch(조건) {
    case 1 :
        //문장
        break;
    defualt :
        //문장
}

주석문

파일 상단, 클래스 상단, 메소드(함수) 상단에 PHPDoc 형태의 주석을 반드시 포함
/**
 * 
 * Enter description here ...
 * @author wyseburn
 *
 */

함수(메소드)내부, 프로그램 상에서는 단행 주석문 // 만 사용

PHP기타

불필요한 quote(', ") 사용금지
echo "$var";
$var = "$var1";

php.ini 설정
register_global = off

mysql 관련 함수
pdo 또는 mysqli 계열 함수만 사용할 것(pdo 추천)

PHP5.3에서 deprecated 된 함수 사용금지(PHP 6.0에서 완전히 제거될 예정임)
http://kr.php.net/manual/en/migration53.deprecated.php

디렉토리구조

외부노출 안되는 디렉토리에 _ 사용
_lib : 라이브러리(함수,클래스)
_model : 모델
_view : 뷰
public/뷰명/img : 이미지
public/뷰명/css : 개별 css
public/뷰명/js : 개별 js
디렉토리 : 일반/컨트롤러 디렉토리

파일명

외부 노출 안되는 파일명에 접두어 사용
func.파일명.php : 함수
class.파일명.php : 클래스
inc.파일명.php : 인클루드되는 파일
ajax.파일명.php : ajax호출파일
파일명_파일명.php : 주체(그룹)_동작(동사)_유형.php - 유형생략가능
 

 


2011. 5. 9. 15:09

PDO 예제

Example#1 Connecting to MySQL

<?php
$dbh 
= new PDO('mysql:host=localhost;dbname=test'$user$pass);
?>

Example#2 Handling connection errors
<?php
try {
   
$dbh = new PDO('mysql:host=localhost;dbname=test'$user$pass);
   foreach (
$dbh->query('SELECT * from FOO') as $row) {
      
print_r($row);
   }
   
$dbh null;
} catch (
PDOException $e) {
   print 
"Error!: " $e->getMessage() . "<br/>";
   die();
}
?>

Example#3 Closing a connection
<?php
$dbh 
= new PDO('mysql:host=localhost;dbname=test'$user$pass);
// use the connection here


// and now we're done; close it
$dbh null;
?>

Example#4 Persistent connections

<?php
$dbh 
= new PDO('mysql:host=localhost;dbname=test'$user$pass, array(
  
PDO::ATTR_PERSISTENT => true
));
?>

Example#5 Executing a batch in a transaction
<?php
try {
  
$dbh = new PDO('odbc:SAMPLE''db2inst1''ibmdb2'
      array(
PDO::ATTR_PERSISTENT => true));
  echo 
"Connected\n";
  
$dbh->setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION);

  
$dbh->beginTransaction();
  
$dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')");
  
$dbh->exec("insert into salarychange (id, amount, changedate) 
      values (23, 50000, NOW())"
);
  
$dbh->commit();
  
} catch (
Exception $e) {
  
$dbh->rollBack();
  echo 
"Failed: " $e->getMessage();
}
?>

Example#6 Repeated inserts using prepared statements
<?php
$stmt 
$dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name'$name);
$stmt->bindParam(':value'$value);

// insert one row
$name 'one';
$value 1;
$stmt->execute();

// insert another row with different values
$name 'two';
$value 2;
$stmt->execute();
?>

Example#7 Repeated inserts using prepared statements
<?php
$stmt 
$dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1$name);
$stmt->bindParam(2$value);

// insert one row
$name 'one';
$value 1;
$stmt->execute();

// insert another row with different values
$name 'two';
$value 2;
$stmt->execute();
?>

Example#8 Fetching data using prepared statements
<?php
$stmt 
$dbh->prepare("SELECT * FROM REGISTRY where name = ?");
if (
$stmt->execute(array($_GET['name']))) {
  while (
$row $stmt->fetch()) {
    
print_r($row);
  }
}
?>

Example#9 Calling a stored procedure with an output parameter

<?php
$stmt 
$dbh->prepare("CALL sp_returns_string(?)");
$stmt->bindParam(1$return_valuePDO::PARAM_STR4000); 

// call the stored procedure
$stmt->execute();

print 
"procedure returned $return_value\n";
?>

Example#10 Calling a stored procedure with an input/output parameter

<?php
$stmt 
$dbh->prepare("CALL sp_takes_string_returns_string(?)");
$value 'hello';
$stmt->bindParam(1$valuePDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT4000); 

// call the stored procedure
$stmt->execute();

print 
"procedure returned $value\n";
?>

Example#11 Invalid use of placeholder

<?php
$stmt 
$dbh->prepare("SELECT * FROM REGISTRY where name LIKE '%?%'");
$stmt->execute(array($_GET['name']));

// placeholder must be used in the place of the whole value
$stmt $dbh->prepare("SELECT * FROM REGISTRY where name LIKE ?");
$stmt->execute(array("%$_GET[name]%"));
?>
 
2010. 5. 20. 14:50

php 이메일, ip 체크하는 정규식 함수


function is_email($email) 

      return preg_match("/^(.+)\\@(.+)\\.(.+)$/", $email); 
}

function is_ip($ip)

    if(preg_match("/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/", $ip, $match)) 
           if($match[1] < 256 && $match[2] < 256 && $match[3] < 256 && $match[4] < 256) 
                return true; 

    return false; 
}
2009. 11. 17. 20:15

hex2bin() 함수


function hex2bin($str) {
    $bin = "";
    $i = 0;
    do {
        $bin .= chr(hexdec($str{$i}.$str{($i + 1)}));
        $i += 2;
    } while ($i < strlen($str));
    return $bin;
}


bin2hex 함수의 반대 버젼
2009. 3. 2. 13:56

utf-8 로 이전하기

utf-8 로 이전하기.

1. MySQL

-- 5.x --
- euckr 스키마 백업
mysqldump --all-databases --no-data --default-character-set=euckr -p > backup.scheme.sql

- euckr 자료 백업
mysqldump --all-databases --no-create-db --no-create-info --default-character-set=euckr -p > backup.data.sql

웬만하면 사용자계정 정보는 암호까지 확실하게 알고있자.
GRANT ALL 쿼리문을 직접 작성하여 가지고 있자.

- UTF-8 을 제대로 지원하기 위해 버전을 5.x 로 올린다.
(varchar(1) 은 1byte 가 아닌 한글자를 의미하게 된다.
set names 만으로 클라이언트의 캐릭터셋을 맞출 수 있다.)
= backup.scheme.sql =
테이블 중 BLOB 형식이나 BINARY 속성 필드에 문자열이 들어가는 곳이 있다면,
TEXT 형식으로 바꾸거나 BINARY 속성을 없앤다.
DEFAULT '0' 같은 잘못된 따옴표를 고친다.
TYPE=MyISAM 같은건 ENGINE=MyISAM 으로 수정한다.
맨 위쪽의 SET NAMES euckr 을 제외한 모든 CHARACTER SET 의 euckr 을 utf8 로 수정한다.

cat backup.scheme.sql | mysql -p --default-character-set=utf8
mysql 설정이 utf8 기준이고, sql 문에 SET NAMES euckr 이 들어있다.
즉, 생성은 utf8 로 되지만, 데이터가 euckr 이라는것을 알고 있으므로,
자동으로 변환되어 들어간다.
이는 iconv 를 이용한 변환보다 안전하다.
(MySQL 의 옛날 버전은 멀쩡한 한글조차 escape 시켜 놓는 경우가 있다.)

= backup.data.sql =
cat backup.data.sql | mysql -p --default-character-set=utf8

- 사용자계정을 GRANT ALL 문으로 다시 만들어준다.
root 지워버리지 않게 주의.


-- old --
이전 MySQL 에 charset 관련 옵션이 없다면,
스키마는
cat backup.scheme.sql | mysql -p --default-character-set=utf8
데이터는
cat backup.data.sql | mysql -p --default-character-set=euckr
로 복구하면 된다.

스키마는 꼭 꼼꼼히 살펴보고 편집하자.
스키마에 한글로 된 주석 같은것이 있다면,
지워버리는것이 속 편하지만,
살리고자 한다면, 편집이 필요하다.
backup.scheme.sql 을 열고 맨 위에
SET NAMES euckr; 을 적어주자.
다른 줄에 SET NAMES 가 없어야 한다.
그리고 CREATE DATABASE, CREATE TABLE 문에 일일히 CHARACTER SET utf8;
을 붙여주자.
편집시 편집기에 의해 캐릭터 셋이 변경되지 않도록,
별 기능 없는 편집기를 이용하자.

2. 파일
모든 파일의 내용을 utf8 로 바꾸자.
조건에 따라 동작이 달라지므로 php 를 이용하자.
/toutf.php
<?php

$f = $_SERVER['argv'][1];
if(!file_exists($f)) {
    echo $f." file not found.\n";
}

$text = file_get_contents($f);
$text8 = @iconv('CP949', 'UTF-8//IGNORE', $text);

$cnt = strlen($text);
$cnt8 = strlen($text8);
if($cnt <= $cnt8) {
    // 제대로 변경이 되었다면 용량이 커졌을 것이다.
    // 용량이 같다면 한글이 없는 것이다.
    rename($f, $f.'.euckr'); // 백업
    file_put_contents($f, preg_replace('/charset=euc-kr/i', 'charset=utf-8', $text8));
    echo $f." file is converted.\n";
} else {
    // 용량이 작아진다면 잘못된 것이다.
    $fp = fopen('/error.txt', 'a');
    fwrite($fp, $f."\n");
    fclose($fp);
}

?>

find /home -type f -name "*.php" -exec php /toutf.php "{}" \;
find /home -type f -name "*.inc" -exec php /toutf.php "{}" \;
find /home -type f -name "*.txt" -exec php /toutf.php "{}" \;
find /home -type f -name "*.html" -exec php /toutf.php "{}" \;
find /home -type f -name "*.htm" -exec php /toutf.php "{}" \;
find /home -type f -name "*.js" -exec php /toutf.php "{}" \;
find /home -type f -name "*.css" -exec php /toutf.php "{}" \;


현재 UTF-8 이 아닌 곳이 없기 때문에,
기억을 더듬어 대충 만들었다.
적용전 백업은 필수다.

에디터는 EmEditor, DreamWeaver CS3 를 추천한다.
FTP 는 WinSCP 4 를 추천한다. 윈도 커멘더 모드로 하면 파일명이 지X 같아도 잘 올리고 받아질 것이다.

WinSCP 의 에디터로 EmEditor 를 설정하면 무적이다.
EmEditor 는 기능이 조금 제한된 free 버전이 있다. 출처 : http://phpschool.com/gnuboard4/bbs/board.php?bo_table=tipntech&wr_id=58038&sca=&sfl=wr_name%7C%7Csubject&stx=%BC%DB%C8%BF%C1%F8&sop=and&page=2