* PHP를 통해서 원격에 있는 이미지를 긁어오거나 복사하고 싶을 때가 많은데 예외상황이 많을 것이다. 한번 예외상황들에 대해서 적어보고, 특히 php.ini를 마음대로 수정못하는 웹호스팅을 하고 있다면 꽤나 골치 아플 일이 많을 것이다.

 

: 일단 첫번째로 확인해야될 제약사항은 php.ini에서 "allow_url_fopen"이 "on" 되어있어야한다는 것이다. 만약 이것이 on 되어있다면 원격의 파일을 꽤나 쉽게 가져올 수 있다.

 

* copy 함수를 이용해서 원격 이미지 가져오기

: 우선 가장 간단하게 가져올 수 있는 방법은 copy 함수를 쓰는 것이다.

copy("http://remotedomain.com/image.jpg", "/tmp/local.jpg");

: 위와 같이 하면 바로 원격의 파일을 로컬로 복사해서 가져올 수 있다.

 

* file_get_contents, file_put_contents 함수를 이용하는 방법

: 위보다 조금은 복잡하게, 그러나 파일의 내용을 수정하고 싶거나 전체 흐름을 조율하고 싶다면 아래와 같이 할수도 있다.

$img = file_get_contents("http://remotedomain.com/image.jpg");
$save = file_put_contents("/tmp/local.jpg");

: 아니면 fwrite를 쓸수도 있다.

$img = file_get_contents("http://remotedomain.com/image.jpg");
$fp = fopen("/tmp/local.jpg", "w");
fwrite($fp, $img);
fclose($fp)
: fopen을 쓰고 싶다면 다소 복잡해지지만 가능은 하다. 물론 위의 allow_url_fopen이 설정되어있다면 가능한 것이다.
$rf = fopen($url, "r");
$fp = fopen("/tmp/local.jpg", "w");

while(!feof($rf)) {
  fwrite($fp, fread($rf, 1), 1);
}
fclose($rf);
fclose($fp);
 
: 아무튼 php.ini에서 "allow_url_fopen"이 설정되어있는 경우는 쉽게 되지만, 안되어있는 경우에는 별도로 curl을 사용해서 가져와야한다. 위의 방법들을 사용하고 싶다면 php.ini에 allow_url_fopen=on으로 설정하거나, 아파치 등 웹서버 설정에서 overwrite할 수 있다면, .htaccess에서 php_value allow_url_fopen on 등으로 설정하면 된다. (PHP 4.3.4 이상 버전 호환)
 
 
* curl을 이용하는 방법
: 웹서버의 제약이나 php의 제약으로 인하여 위의 allow_url_fopen을 설정할 수 없다면, 원격의 url에 fopen을 사용하지 못하면 직접 접속해서 가져와야할 것이다. 가장 쉽게는 curl을 사용하면 된다.
$fp = fopen("/tmp/loca.jpg", "w");

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://remotedomain.com/image.jpg");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)");
curl_setopt($ch, CURLOPT_FILE, $fp);

curl_exec($ch);

fclose($fp);
curl_close($ch);
 

 

: 이외에서 http모듈을 사용하는 방법도 있지만, 아무리 막혀있어도 curl에서는 해결이 될 것이므로 이정도면 원격 URL의 파일을 가져오는데에는 성공할것이라 생각한다.

 

원격 URL의 파일을 로컬로 가져오기 끝.

 

출처: https://unikys.tistory.com/345 [All-round programmer:티스토리]

블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,

특정 날짜가 해당 월의 몇주차인지 계산해주는 함수입니다.

 

사용법 :

$nowJucha = getWeekInfo(date("Y-m-d"));

또는

$nowJucha = getWeekInfo(date("2021-03-17"));

 

function getWeekInfo($_date)
{
    $BASIC_DOW = 1; // 1(mon) ~ 7(sun)
    list($yy, $mm, $dd) = explode('-', $_date);
    
    $dow = date('N', mktime(0, 0, 0, $mm, 1, $yy));
    
    if ($dow <= $BASIC_DOW)
    {
        $diff = $BASIC_DOW - $dow;
        $srt_day = $diff+1;
    } else {
        $diff = 7-$dow;
        $srt_day = $diff + $BASIC_DOW + 1;
    }

    if ($dd < $srt_day)
    {
        $new_date = date('Y-m-d', mktime(0, 0, 0, $mm, 0, $yy));
        return getWeekInfo($new_date);
    } else {
        $wom = ceil(($dd-($srt_day-1))/7);

        // 이곳을 수정하면 원하시는 결과로 리턴하셔도 됩니다.
        $new_date = (int)$mm. '-' .$wom; 
        return $new_date;
    }
}

 

즐프하세요~

블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,

스케줄러나 업무일지등을 개발하다보면 날짜관련 컨트롤이 필요할때가 많습니다.

이때 애매한게.. 주간 날짜를 구하는거죠..

이번주 시작일과 끝날짜  이전주, 다음주 날짜 범위를 구하는 방법입니다.

 

$today = time();
$week = date("w");

$week_first = $today-($week*86400);
$week_last = $week_first+(6*86400);

지난주 = date("Y-m-d",$week_first-(86400*7))." ~ ".date("Y-m-d",$week_last-(86400*7));
이번주 = date("Y-m-d",$week_first)." ~ ".date("Y-m-d",$week_last);
다음주 = date("Y-m-d",$week_first+(86400*7))." ~ ".date("Y-m-d",$week_last+(86400*7));

 

응용해서 $today 부분을 특정 날짜로 하면 그날짜가 속한 주간 날짜범위를 구하실 수 있습니다.

 

$today = mktimemktime(23,59,59,03,17,2021);

 

이런식으루요~

 

그럼 즐프들 하십시요!

블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,


Fatal error: Allowed memory size of 134217728 bytes exhausted

( PHP 메모리 부족 에러 )



PHP 프로그래밍중  File I/O 를 다루거나.. 파일 다운로드, 엑셀파일 출력 등을 다루다보면,


위와같은 메모리 부족 에러를 접하게 되는 경우가 있습니다.


PHP 는 기본적으로 메모리 제한 기본값을 128M 로 되어있습니다.


이럴경우 해당 설정 값을 변경해 주면 되는데요..


phpinfo();  명령을 통해서 memory_limit 값을 확인해 보신 후 해당 값을 조정해 주시면 문제를 해결 할 수 있습니다.


그 조치 방법으로는.. php.ini 파일을 찾아서 해당 값을 변경해 주는 방법인데요.


php.ini 파일을 열어보시면 아래와 같은 부분을 찾으실 수 있습니다.



위 값은 제가 기본 128M 인 값을 512M 으로 늘려준 것이구요.


이렇게 변경한 후 아파치를 재기동 하시면 반영이 되어집니다.


혹은 다른 방법으로..


해당 php 파일에서



ini_set('memory_limit','512M');


이와같이 ini_set 명령으로 설정값을 변경 반영하는 방법이 있습니다.


이 방법은 현재 php 파일에서만 유효합니다.


그럼 즐프하세요~

블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,


php 에서 ZipArchive 를 사용하려 하는데.. class 'ZipArchive' not found in..  이런 에러가 발생을 한다면?


결국엔 libzip 을 설치해 주어야 합니다.


이는 pecl 을 이용해서 간단히 설치를 할 수도 있지만..  


php.net 에서 최종버전 또는 버전을 선택하여 받아서 설치할 수 있습니다.


centos (리눅스계열) 에서의 설치를 예로 들겠습니다.



1. http://pecl.php.net/package/zip  사이트에 접속하여 사용할 버전을 다운로드 합니다.





2. 파일을 서버에 올린 후 설치 작업을 진행합니다.  (1.13.2 버전을 받은걸로 가정합니다.)


//모듈 이동

#mv zip-1.13.2.tgz /home/


//압축 해제

#tar xvfz zip-1.13.2.tgz


//디렉터리 이동

#cd zip-1.13.2


//phpize 실행

#phpize


//만약 phpize가 오류가 나면 phpinfo에서 include_path 의 위치를 확인합니다.

//저 같은 경우는 extension_dir가 /usr/local/php/lib/php 이였으므로 php 설치 폴더의 위치를 알수 있었습니다.

//혹은 yum install php-devel 등으로 설치하면 됩니다.

#/usr/local/php/bin/phpize


//모듈 configure

./configure --with-php-config=/usr/local/php/bin/php-config --enable-zip && make


//모듈 파일 이동

#cd modules/

#cp zip.so /usr/local/php/lib/php/extensions/ ;마찬가지로 phpinfo에서 extension위치 확인


//extension 경로 추가

#vim /usr/local/apache/conf/php.ini


extension_dir="/usr/local/php/lib/php/extensions"


extension="zip.so" 


//아파치 재시작

#/etc/init.d/httpd restart 



3. phpinfo() 내용을 확인하여.. 정상적으로 설치가 되어졌는지 확인합니다.


이런부분이 확인되어지면 됩니다.


그럼 php 에서 ZipArchive class 를 이용해서 압축, 압축해제 등의 작업을 진행하실 수 있습니다.~


블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,

php로 웹상의 파일 읽기(원격 리소스 읽기)

이 글은 http://www.php-mysql-tutorial.com/wikis/php-tutorial/reading-a-remote-file-using-php.aspx에 있는 글을 번역한 것입니다


php로 웹상(원격)에 있는 파일을 읽는 방법으로는 아래의 4가지 방법을 사용해서 구현이 가능하다

  1. fopen() 함수 사용
  2. file_get_contents() 함수 사용
  3. cURL 라이브러리 사용
  4. php의 소켓통신 함수들을 사용

1번과 2번 방법을 사용하기 위해서는 fopen wrapper 가 사용 가능해야한다. 이 fopen wrapper 파라미터는 php.ini에 정의되어 있으나, ini_set()을 사용해서 실행시간에 바꿀수는 없다.

이 두 방법을 쓸수 있는지의 여부는 아래 코드로 확인할수 있다

<?php
if (ini_get('allow_url_fopen') == '1') {
   // fopen() 이나 file_get_contents() 사용
} else {
   // curl 이나 함수 직접 작성
}

1. fopen() 함수 사용

fopen()을 사용하는 법은 local 파일을 읽는것 만큼 쉽다. 유일하게 다른점은 fopen()함수 내에 파일명 대신 URL을 적는다는 것이다. 아래 예제를 보자.

<?php
// 원격 파일을 사용하기 전에 성공적으로 open 되었는지 확인
if ($fp = fopen('http://www.google.com/', 'r')) {
   $content = '';
   // 전부 읽을때까지 계속 읽음
   while ($line = fread($fp, 1024)) {
      $content .= $line;
   }

   // content 사용
   // ...
} else {
   // 파일 open시 에러 발생
}

위 코드중 while 반복문의 fread() 함수는 한 루프 안에서 1024 바이트의 데이터를 읽기 위해 사용된다. 이 코드는 아래와 같이 쓸수도 있다.

<?php
// 원격 파일을 사용하기 전에 성공적으로 open 되었는지 확인
if ($fp = fopen('http://www.google.com/', 'r')) {
   $content = '';
   // 전부 읽을때까지 계속 읽음
   while ($line = fgets($fp, 1024)) {
      $content .= $line;
   }

   // content 사용
   // ...
} else {
   // 파일 open시 에러 발생
}

fread() 대신에 최대 1024바이트의 라인 한줄을 읽는 fgets()를 사용했다. 첫번째 코드가 두번째보다 좀더 선호되는 방식이다.

원격에 있는 파일이 300줄 짜리 50KB 파일이라고 생각해보면, 첫번째 코드는 루프가 15번 정도 돌테지만 두번째 코드는 300번의 루프가 실행되야 한다

만약 함수호출 비용과 시간을 고려중이라면 첫번째 방법이 확실히 나은 방법이다

2. file_get_contents() 함수 사용

가장 간단해서 내가 가장 선호하는 방법이다. 단지 파라메터를 url로 주고 함수를 호출하기만 하면 된다. 한가지 기억해야할 점은 리턴받은 값을 사용하기 전에 error가 리턴 됬는지 확인 먼저 해야한다는 것.

<?php
$content = file_get_contents('http://www.google.com/');
if ($content !== false) {
   // content 사용
} else {
   // error 발생
}

3. cURL 라이브러리 사용

위의 두 방법과는 다르게 CURL을 쓰는 방법은 딱 부러지게 설명하기 힘들다. 이 라이브러리는 (http뿐만 아니라) 다른 프로토콜 간의 연결과 통신하는 데에 매우 유용하기 쓰이긴 하지만 배우는데 시간을 좀 들여야 한다. 또 다른 문제는 모든 web host들(서버)이 이 php 라이브러리를 설치하지는 않았다는것. 따라서 이 방법을 쓰기 전에 해당 라이브러리가 설치되어 있는지 먼저 확인 해야한다

다음은 이 CURL라이브러리를 활용해서 원격 파일을 여는 간단한 예제다

<?php
// curl이 설치 되었는지 확인
if (function_exists('curl_init')) {
   // curl 리소스를 초기화
   $ch = curl_init(); 

   // url을 설정
   curl_setopt($ch, CURLOPT_URL, 'http://www.google.com'); 

   // 헤더는 제외하고 content 만 받음
   curl_setopt($ch, CURLOPT_HEADER, 0); 

   // 응답 값을 브라우저에 표시하지 말고 값을 리턴
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 

   // 브라우저처럼 보이기 위해 user agent 사용
   curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0'); 

   $content = curl_exec($ch); 

   // 리소스 해제를 위해 세션 연결 닫음
   curl_close($ch);
} else {
   // curl 라이브러리가 설치 되지 않음. 다른 방법 알아볼 것
}

몇가지 경우에는 file_get_contents()나 fopen() 을 쓰는것보다 CURL이 더 빠르다. 이것은 CURL이 기본적으로 압축 프로토콜을 사용하기 때문이다 (예를들면 gzip).

크고 작은 많은 사이트에서 bandwidth를 줄이기 위해 그들 페이지에서 gzip 압축을 사용한다. 이 사이트도 gzip 압축을 사용했고, bandwidth가 절반으로 줄었다. 만약 기다리기 싫어하는 타입이라면 CURL이 가장 적당할것이다

4. php의 소켓통신 함수들을 사용

최악의 경우에는 서버의 fopen wrapper 옵션도 꺼져있고, CURL 라이브러리도 인스톨 되지 않았을수도 있다. 이 상황에서는 우리가 쓸 함수를 직접 만들어야 한다.

우리의 함수는 대상 파일의 url 파라미터 한개를 갖는 getRemoteFile() 함수로 명명했다. 대략적인 뼈대는 아래와 같다

<?php
function getRemoteFile($url)
{
   // 1. host name과 url path 값을 획득

   // 2. 원격 서버에 접속

   // 3. 파일을 얻기위해 필요한 헤더들을 전송

   // 4. 원격 서버로부터 응답 받음

   // 5. header 부분 걷어냄

   // 6. 파일 content 리턴
}

url에서 host name과 url path 를 추출하기위해서는 parse_url() 함수를 이용하면 된다. 이 함수에 넘겨진 url은 다음 항목들로 분리될 것이다

  • scheme
  • host
  • port
  • user
  • pass
  • path
  • query
  • fragment

예를들면, http://www.php-mysql-tutorial.com/somepage.php 은 아래와 같이 리턴된다

<?php
Array
(
    [scheme] => http
    [host] => www.php-mysql-tutorial.com
    [path] => /somepage.php
)

만약 http://myusername:mypassword@www.php-mysql-tutorial.com/somepage.php?q=whatsthis#ouch 라면 아래와 같이 리턴된다

<?php
Array
(
    [scheme] => http
    [host] => www.php-mysql-tutorial.com
    [user] => myusername
    [pass] => mypassword
    [path] => /somepage.php
    [query] => q=whatsthis
    [fragment] => ouch
)

우리가 관심있는것은 host, port, path, query 값 뿐이다

원격 서버와의 connection을 생성하기는 위해서 fsockopen()을 사용한다. 이 함수는 [hostname, port number, error number 포인터, error message 포인터, 시간제한] 5개의 인자를 가지고 있다

<?php
function getRemoteFile($url)
{
   // host name 과 url path 값을 획득
   $parsedUrl = parse_url($url);
   $host = $parsedUrl['host'];
   if (isset($parsedUrl['path'])) {
      $path = $parsedUrl['path'];
   } else {
      // url이 http://www.mysite.com 같은 형식이라면
      $path = '/';
   }

   if (isset($parsedUrl['query'])) {
      $path .= '?' . $parsedUrl['query'];
   } 

   if (isset($parsedUrl['port'])) {
      $port = $parsedUrl['port'];
   } else {
      // 대부분의 사이트들은 80포트를 사용
      $port = '80';
   }

   $timeout = 10;
   $response = '';
   // 원격 서버에 접속한다
   $fp = @fsockopen($host, $port, $errno, $errstr, $timeout );

   if( !$fp ) {
      echo "Cannot retrieve $url";
   } else {
      // 필요한 헤더들 전송
      fputs($fp, "GET $path HTTP/1.0\r\n" .
                 "Host: $host\r\n" .
                 "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3\r\n" .
                 "Accept: */*\r\n" .
                 "Accept-Language: en-us,en;q=0.5\r\n" .
                 "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" .
                 "Keep-Alive: 300\r\n" .
                 "Connection: keep-alive\r\n" .
                 "Referer: http://$host\r\n\r\n");

      // 원격 서버로부터 response 받음
      while ( $line = fread( $fp, 4096 ) ) {
         $response .= $line;
      }

      fclose( $fp );

      // header 부분 걷어냄
      $pos      = strpos($response, "\r\n\r\n");
      $response = substr($response, $pos + 4);
   }

   // 파일의 content 리턴
   return $response;
}

위의 코드에서는 9줄의 헤더 정보를 보내지만 사실 처음 2줄만 필수사항이다. 따라서 이렇게만 보내도 된다

<?php
fputs($fp, "GET $path HTTP/1.0\r\n" . "Host: $host\r\n\r\n");

아마 대부분의 경우 잘 동작할테지만 항상 잘 동작하는것은 아니다. 열고자 하는 파일들은 원격 서버에 저장되어 있기때문에, 원격 서버가 request에 response 하는지 안하는지에 달려있다

몇몇 서버는 request 헤더에 referer 항목이 없다면 block 할것이고, 몇몇은 특정 user agent 만 받아들일 것이다. 또 어떤 것들은 cookie가 설정되어 있는 header만 받을 것이다

특정 원격 파일을 여는데에 어떤 헤더가 보내져야 하는지 알고 싶다면 파이어폭스와 live http headers plugin 툴을 사용해 보라. 작고 강한 툴이다



블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,


php 에서 MSSQL 연동하기 ( FreeTDS 이용)


URL : http://www.freeTDS.org

stable 버전을 다운받으면 된다.

구분하기 쉬우라고 다운받아서 /usr/local/src/APM 아래에 옮겨버렸다.

아 맞다 우선 설치환경부터

OS : CentOS 5.3
php : php-5.2.10
apache : httpd-2.2.11
SQL : MSSQL- ???

디비 버전을 모르겠다. 설치와는 완전 무관하기에 그냥 넘어간다.

다운받은 파일의 압축을 푼다.

cd /usr/local/src/APM/
tar xvzf freetds-stable.tgz

압축을 풀면 freetds-0.82 라는 폴더가 생긴다. 이동하자. 현재 버전이 0.82 인가 보다.

cd freetds-0.82

이제 설치하자

./configure --prefix=/usr/local/server/freetds --with-tdsver=8.0 --disable-odbc --disable-debug --enable-msdblib
make && make install

php를 재설치해야 한다.

./configure --prefix=/usr/local/server/php --with-apxs2=/usr/local/server/apache/bin/apxs --with-mysql=/usr/local/server/mysql --with-config-file-path=/usr/local/server/apache/conf --disable-debug --enable-safe-mode --enable-track-vars --enable-sockets --with-charset=utf8 --with-xml --with-language=korean --enable-calendar --enable-sysvsem=yes --enable-sysvshm=yes --enable-ftp --enable-magic-quotes --enable-gd-native-ttf --enable-url-includes --enable-inline-optimization --enable-bcmath --with-jpeg --with-png --with-zlib --with-jpeg-dir=/usr --with-png-dir=/usr/lib --with-freetype-dir=/usr --with-libxml-dir=/usr --enable-exif --with-gd --with-ttf --with-gettext --enable-sigchild --enable-mbstring --with-mssql=/usr/local/server/freetds

기존 옵션에 하나만 더 추가했다.

make && make install

아파치를 재실행한다.

/etc/init.d/httpd restart

php 정보를 확인하면 다음과 같은 mssql 이 추가된 것을 볼 수 있다.


한글이 깨지는 것을 막기 위해 php.ini 설정을 다음과 같이 수정해준다.

cd /usr/local/server/apache/conf/
vim php.ini

인코딩은 각자의 웹 환경에 맞춰서 입맛대로 바꿔주면 되겠다.

아래와 같은 코드로 테스트를 해보자.

[msdbtest.php]

<html>
<head>
    <title>mssql 접속 테스트</title>
</head>
<body>
일본어 데이터들어 분류번호와 분류명을 가져오는걸 테스트해본다.
<br><br>
<?php
$DB_IP        ="***.***.***.***:1433"; //기본 포트port 1433
$DB_USERID    ="*******";
$DB_USERPW    ="**********";
$DB_NAME      ="******";

$conn = mssql_connect($DB_IP,$DB_USERID,$DB_USERPW);
$result = mssql_select_db($DB_NAME, $conn);
$result = mssql_query("SELECT term_name, term_remark FROM terms1 WHERE LEN(term_remark)<=5");

?>
<table border=1>
<tr>
<td>번호</td>
<td>분류항목</td>
<td>분류어</td>
</tr>
<?
$i=1;
while ($row = mssql_fetch_row($result)) {
    $resultData="<tr><td>".$i++."</td><td>".$row[1]."</td><td>".$row[0]."</td></tr>";
    echo $resultData;
}

mssql_close($conn); 

?>
</table>
</body>
</html>

현재 구축되어있는 mssql 에 접속해서 읽어왔기 때문에 디비 생성이나 데이터 입력하는 부분은 빠져있다.

이 포스트를 참조하시는 분들은 본인의 환경에 맞춰서 php 코드를 수정하면 결과를 확인할 수 있을것이다.

블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,

Assigning the return value of new by reference is deprecated

 

PHP 개발 중 위와같은 오류가 발생하는 경우는

 

참조 시키는 경우 바로 받아서 사용할 수 없는 경우의 경고 메세지 입니다.

 

물론 이는 php.ini 의 설정 (에러메세지 출력 관련)에 따라서 안나올 수도 있습니다.

 

만약 경고를 유발시키지 않으시려면...

 

$a  = & new classname();

 

이런식으로 바로 참조 시키면 안되고..

 

$tmp = new classname();

$a = &$tmp;

 

이런식으로 한번 거쳐서 해주시면 아무런 문제가 없답니다~

 

즐프하세요.

 

 

블로그 이미지

슬픈외로움

개발이 어려워? 모든것엔 답이있다...

,