본문으로 건너뛰기

"php" 태그로 연결된 49개 게시물개의 게시물이 있습니다.

모든 태그 보기

Nginx for Windows - 3. Virtual Host

· 약 2분

Nginx - 2. PHP 연동에서 이어집니다.

conf\nginx.conf 파일에서 쉽게 추가가 가능하다.

nginx.conf
http {
# 기존에 있던 default 설정
server {
...
}

# 이렇게 server 구문을 하나 더 추가한다.
server {
listen 8000;
# 서버 주소
server_name local.test.com;
index index.php;
# 서버 경로
root D:/workspace/testphp/;

location / {
try_files $uri /index.php$is_args$args;
}

# php 사용을 개별로 추가해야한다.
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9123;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
...
}

위 소스는 index.php를 라우터로 사용하기 위해 설정되었으므로, 17, 22, 23줄의 구문은 없어도 된다.

Host 파일 수정

Apache Virtual Host 설정 문서의 Host 파일 수정 메뉴를 따라 진행하면 된다.

연동 확인

nginx 서비스를 재시작하고 확인한다.

Nginx for Windows - 2. PHP 연동

· 약 3분

Nginx 설치에서 이어집니다.

Nginx를 설치했으니 PHP와 연동을 해보자.

이전 포스트로 대체한다. Apache버전은 상관이 없으니 x64 Thread Safe 버전으로 3번까지만 따라서 설치하면된다.

연동

nginx 설정

Nginx 폴더에서 conf/nginx.conf를 수정한다.

http {
...
server {
...
location / {
root html;

# index.php를 추가
index index.html index.htm index.php;
}
...
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
# 이 부분 주석을 모두 제거해준다.
location ~ \.php$ {
root html;

# nginx에서 9123포트를 추천한다.
fastcgi_pass 127.0.0.1:9123;
fastcgi_index index.php;

# SCIPRT를 $document_root 로 변경
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
...
}
}

php-cgi 설정

nssm을 사용하는 방법과 배치 파일을 만드는 방법이 있는데 전자를 추천한다. bat 파일은 nginx restart를 할 때마다 따로 실행해줘야한다.

다른 포스팅에는 php-cgi 서비를 cmd에서 sc create 명령어를 사용하여 등록하는 부분이 있는데 windows10 환경에서 서비스가 1053 오류를 뱉으며 죽는다. 시간 낭비하지 말자.

nssm

nginx에 지난 스텝에서 설치한 nssm을 사용한다. nginx\nssm\win64 폴더로 이동해 php 등록 커맨드를 입력한다.

./nssm.exe install php

php-cgi 경로를 선택한 뒤 아래 명령어를 Arguments 필드에 넣어준다.

# 경로를 알맞게 수정해주자.
D:\php7\php-cgi.exe -b 127.0.0.1:9123 -c D:\php7\php.ini

image from hexo

서비스를 실행한다. image from hexo

실행이 안되는 경우 arguments에 앞의 경로를 제거하고 -b 127.0.0.1:9123 -c D:\php7\php.ini 만 입력해준다.

bat

배치 파일을 만들어 nginx가 실행 되기전만 php-cgi를 킬 수도 있다.

@ECHO OFF
ECHO Starting PHP CGI...
set PATH=D:\php7;%PATH%
D:\php7\php-cgi.exe -b 127.0.0.1:9123 -c D:\php7\php.ini

위 소스의 경로를 알맞게 수정한 뒤 start-php-cgi.bat으로 저장 후 실행한다.

확인

**nginx\html\**에 index.php를 만든다.

index.php
<?php
phpinfo();

localhost:88/index.php로 접속한다. image from hexo

여담

한 방에 설치하는 방법도 있지만 현재 버전까지는 C:\말고 D:\에 php를 설치한 사람에 대한 배려는 없다. (bat 파일을 건드려봐도 dll 안에 로깅하는 부분에서 오류 발생)

Nginx for Windows - 1. Setup

· 약 2분

Windows에서 Nginx로 로컬 웹서버를 돌려보자.

다운로드

Nginx 홈페이지에서 Windows 버전을 다운로드 받는다. image from hexo

압축을 풀어 원하는 위치(D:\nginx)로 옮겨주자

설정

apache, iis가 중복이 된다면 conf/nginx.conf 파일을 열어 포트 설정을 바꿔준다.

nginx.conf
http {
...
server {
listen 88; # 여기를 수정해주자.
server_name localhost;
...
}
...
}

실행

nginx.exe를 더블 클릭한다.

서비스 등록

실행은 되었지만 서비스를 등록해야 자동으로 실행되고 on/off를 관리하기가 쉽다. 다른 포스트에 있는 github의 2011년 엔진엑스 서비스 등록 소스는 찾아봐도 없길래 새로운 방법으로 등록한다.

nssm

nssm에서 서비스 등록 프로그램을 다운받는다. image from hexo

압축을 풀어주고(D:\nginx\nssm-2.24) 자신의 windows bit에 맞는 폴더에서 nssm.exe를 커맨드로 실행하면 된다.

$ ./nssm.exe install nginx

nginx 경로를 잡아주고 Install Service 버튼을 클릭한다. image from hexo

실행

services.msc를 실행해 서비스 창을 열어 nginx를 실행한다. image from hexo

확인

image from hexo

Nginx - 2. PHP 연동으로 이어집니다.

curl을 사용하지 않는 http 통신

· 약 3분

curl 기능이 확장되어있지 않아 http 통신을 할 수 없는 경우가 있다. fsockopen 메소드를 사용해 같은 기능을 할 수 있다.

GET

<?php
/**
* [getData 외부파일을 GET 방식으로 읽기]
* @param [string] $str [url]
* @param [array] $data [parameters]
* @return [string] [내용]
*/
function getData($str, $data) {
$url = parse_url($str);

switch(strtoupper($url['scheme'])) {
case 'HTTP':
if (!isset($url['port'])) {
$url['port'] = 80;
}
break;
case 'HTTPS':
$url['ssl'] = 'ssl://';
if (!isset($url['port'])) {
$url['port'] = 443;
}
break;
}

$fp = @fsockopen($url['ssl'].$url['host'], $url['port'], $errno, $errstr, 10);
if ($fp) {
fwrite($fp, "GET $url[path]?".http_build_query($data)." HTTP/1.0\r\nHost: $url[host]\r\n");
while (!feof($fp)) {
$out .= fread($fp, 1024);
}

fclose($fp);
$out = explode("\r\n\r\n",$out);
array_shift($out);
$out = implode("",$out);
}

return $out;
}

POST

<?php
<?
/**
* [postData 외부파일을 POST 방식으로 읽기]
* @param [string] $str [url]
* @param [array] $data [parameters]
* @param [int] $sleepMs [연결지연ms]
* @return [string] [내용]
*/
function postData($str, $data, $sleepMs=0) {
$url = parse_url($str);

switch(strtoupper($url['scheme'])) {
case 'HTTP':
if (!isset($url['port'])) {
$url['port'] = 80;
}
break;
case 'HTTPS':
$url['ssl'] = 'ssl://';
if (!isset($url['port'])) {
$url['port'] = 443;
}
break;
}

$data_string = http_build_query($data);
$referrer = $_SERVER['SCRIPT_URL'];

$request = "POST {$url[path]} HTTP/1.1\r\nHost: {$url[host]}\r\nReferer: {$referrer}\r\n";
$request .= "Content-type: application/x-www-form-urlencoded\r\n";
$request .= "Content-length: " . strlen($data_string) . "\r\n";
$request .= "Connection: close\r\n\r\n";
$request .= "{$data_string}\r\n";

$fp = @fsockopen($url['ssl'].$url[host], $url[port], $errno, $errstr, 10);
if ($fp) {
fwrite($fp, $request);
usleep(($sleepMs * 1000));

do {
$header .= fread($fp, 1);
} while (!preg_match('/\\r\\n\\r\\n$/', $header));

if (preg_match('/Transfer\\-Encoding:\\s+chunked\\r\\n/', $header, $matches)) {
// check encoding
do {
$byte = $chunk_size = "";
do {
$chunk_size .= $byte; $byte = fread($fp, 1);
} while ($byte != "\r");
fread($fp, 1);
$chunk_size = hexdec($chunk_size);
if ($chunk_size){
$out .= @fread($fp, $chunk_size);
}
fread($fp, 2);
} while ($chunk_size);

} else if (preg_match('/Content\\-Length:\\s+([0-9]*)\\r\\n/', $header, $matches)) {
$out = fread($fp,$matches[1]);

} else {
while (!feof($fp)) {
$out .= fread($fp, 4096);
}
}

fclose($fp);
}

return $out;
}

예제

<?php
$param = array(
'data1' => '1',
'data2' => '2'
);

// get 요청
$get_data = getData('http://your.apiurl.com', $param);
// post 요청
$post_data = postData('http://your.apiurl.com', $param);
?>

설명

fsockopen 으로 소켓을 연 뒤 해당 host 로 request 만들어 전송한다.

stream 을 사용해 통신하는 방법도 있다.

sleep()을 사용해야할 때

· 약 2분

php에서 sleep() 메소드의 사용법은 이렇다.

1sec_delay.php
<?php
// sleep ( int $seconds )
sleep(1);

// usleep ( int $micro_seconds )
usleep(1000000);

단순히 시간을 지연시키는 이 메소드를 어디에 사용하는 걸까?

Curl 또는 file_get_contents로 내용을 가져올 때 지연없이 request를 보내면 차단을 당하거나 정상적인 응답이 오지 않을 수 있다. 요청을 보낸 후 sleep을 사용해 지연호출을 한다.

Crawling

웹 크롤링 중 호출이 일정시간이상되야 응답을 돌려주는 경우가 있다. 요청을 닫기 전에 sleep을 사용해 연결시간을 늘려준다.

Batch Update

많은 데이터를 cron을 사용해 update를 할 때 테이블이 Lock이 되는 경우를 방지하기 위해 사용한다.

<?php
foreach ($dummy as $data) {
// 5초가 걸리는 쿼리
DB::query("UPDATE ...");

// 5초를 지연시켜 그동안에 호출된 다른 로직을 실행할 수 있게 한다.
sleep(5);
}

이 방법보다 테이블이 Lock 되지않게 Update Query를 만드 것이 더 바람직하다.

Vimeo Upload API - 2. PHP API

· 약 8분

Vimeo Developers 등록에서 이어집니다.

Vimeo Libraries에서 원하는 API를 선택하면 된다. Server Libraries PHP에서 Download를 클릭하면 Github로 이동하고 Installation을 참조하면 된다.

composer

composer가 있으면 쉽게 설치할 수 있다.

$ composer require vimeo/vimeo-api

직접 설치

v1.2.5를 다운 받고 원하는 곳에 압축을 푼 뒤 class를 load한다.

<?php
require("/path/to/vimeo.php/autoload.php");
?>

설정 변경

vimeo.php\config.json 파일을 열어 client_id, client_secret, access_token 값을 수정하자.

Upload API 사용

vimeo.php\example\upload.php를 커스터마이징 해보자.

기본 예제 소스

example\upload.php
<?php
use Vimeo\Vimeo;
use Vimeo\Exceptions\VimeoUploadException;

$config = require(__DIR__ . '/init.php');
if (empty($config['access_token'])) {
// 액세스 토큰이 없을시 로깅 로직 추가
// throw new Exception('액세스 토큰 없이 업로드 할 수 없다.
// 개발자 앱 페이지에서 액세스 토큰을 발급 받거나 auth.php를 이용해라.');
}
$lib = new Vimeo($config['client_id'], $config['client_secret'], $config['access_token']);
// argv 대신 업로드할 파일경로의 배열을 넣으면 된다.
$files = $argv;
array_shift($files);
// 업로드된 트랙을 체크하는 배열
$uploaded = array();
// 업로드 로직 시작
foreach ($files as $file_name) {
// 업로드 시작 로깅
// print 'Uploading ' . $file_name . "\n";
try {
// Vimeo 서버에 업로드하고 해당 파일의 uri을 받는다.
$uri = $lib->upload($file_name);
// 해당 파일의 정보를 요청한다.
$video_data = $lib->request($uri);
// 업로드가 성공한 파일의 링크를 받는다.
$link = '';
if($video_data['status'] == 200) {
$link = $video_data['body']['link'];
}
// 로깅을 위해 저장
$uploaded[] = array('file' => $file_name, 'api_video_uri' => $uri, 'link' => $link);
}
catch (VimeoUploadException $e) {
// 업로드 오류 발생시 예외처리
// print 'Error uploading ' . $file_name . "\n";
// print 'Server reported: ' . $e->getMessage() . "\n";
}
}
// 결과 로깅 및 파일 링크 표시
// print 'Uploaded ' . count($uploaded) . " files.\n\n";
// foreach ($uploaded as $site_video) {
// extract($site_video);
// print "$file is at $link.\n";
// }

커스터마이징

25번째 줄의 request 요청에 추가로 영상정보를 변경하게 요청할 수 있다. 영상정보를 가져오는건 변하지 않는다.

<?php
/**
* [lib->request function]
* 해당 URI를 대상으로 데이터를 받아오고
* PATCH 메소드를 이용해서 그 동영상의 Metadata를 수정하는 함수
*
* @param {[string]} uri [업로드 된 동영상 주소]
* @param {[array]} options [파라미터 배열(json 형식의 배열타입)]
* @param {[string]} method [요청할 메소드 타입(수정은 PATCH)]
* @return {[video]} video_data [비디오 데이터]
*/
$video_data = $lib->request($uri, array(
'name' => '동영상 이름',
'description' => '동영상 설명',
'embed' => array( // embed시의 옵션
'buttons' => array(
'like' => false, // 좋아요 버튼
'watchlater'=> false, // 나중에보기 버튼
'share' => false, // 공유 버튼
'embed' => false, // embed 버튼
'fullscreen'=> false // 전체화면 버튼
),
'logos' => array(
'vimeo' => false // 비메로 로고
),
'title' => array(
'owner' => 'hide', // 제작자 정보
'portrait' => 'hide', // 제작자 로고
'name' => 'hide' // 제작자 이름
),
'playbar' => false // 재생바
)
), 'PATCH');
?>

옵션은 해당 endpoints 참조하자. image from hexo

video_data endpoint

업로드된 파일의 response data에는 파일 metadata가 들어있다. $video_data['body']['키값'] 으로 접근하면 된다. 입맛에 맞게 사용해보자.

{
"uri": "영상 vimeo 링크",
"name": "영상 제목",
"description": "영상 설명",
"link": "영상 vimeo 링크",
"duration": 재생 시간,
"width": 가로 크기,
"language": 언어,
"height": 세로 크기,
"embed": {
"uri": null,
"html": "iframe 영상 링크",
"buttons": {
"like": 좋아요 버튼 여부,
"watchlater": 나중에보기 버튼 여부,
"share": 공유 버튼 여부,
"embed": embed 버튼 여부,
"hd": 고화질 버튼 여부,
"fullscreen": 전체화면 버튼 여부,
"scaling": 스케일링 버튼 여부
},
"logos": {
"vimeo": 비메오 로고 여부,
"custom": {
"active": 커스텀 로고 여부,
"link": 커스텀 로고 링크,
"sticky": sticky 여부
}
},
"title": {
"name": 제작자 이름 display 설정,
"owner": 제작자 정보 display 설정,
"portrait": 제작자 로고 display 설정
},
"playbar": 재생바 여부,
"volume": 볼륨바 여부,
"color": "색상 헥스코드"
},
"created_time": "생성일시 gmt",
"modified_time": "변경일시 gmt",
"release_time": "노출일시 gmt",
"content_rating": [
"safe"
],
"license": "라이센스",
"privacy": {
"view": "노출 설정",
"embed": "embed 노출 설정",
"download": 다운로드 여부,
"add": 추가 여부,
"comments": "댓글 허용 설정"
},
"pictures": {
"uri": "영상 대표 사진 링크",
"active": 사진 여부,
"type": "custom",
"sizes": [
{
"width": 100,
"height": 75,
"link": "사이즈별 링크"
},
...
],
"resource_key": "접근 키"
},
"tags": [태그 배열],
"stats": {
"plays": 재생 수
},
"metadata": {
"connections": {
"comments": {
"uri": "댓글 링크",
"options": [
"GET",
"POST"
],
"total": 0
},
"credits": {
"uri": "크레딧 링크",
"options": [
"GET",
"POST"
],
"total": 0
},
"likes": {
"uri": "좋아요 링크",
"options": [
"GET"
],
"total": 0
},
"pictures": {
"uri": "사진 링크",
"options": [
"GET",
"POST"
],
"total": 0
},
"texttracks": {
"uri": "텍스트 트랙 링크",
"options": [
"GET",
"POST"
],
"total": 0
},
"related": null
},
"interactions": {
"watchlater": {
"added": false,
"added_time": null,
"uri": "나중에보기 링크"
}
}
},
"user": {
"유저정보 및 접근 경로"
},
"review_link": "리뷰 다이렉트 링크",
"files": [
{
"quality": "파일 화질",
"type": "파일 타입",
"width": 파일 가로,
"height": 파일 세로,
"link": "파일 다이렉트 링크",
"created_time": "파일 생성일시",
"fps": 주사율,
"size": 파일 크기,
"md5": "토큰",
"link_secure": "파일 다이렉트 시큐어 링크"
},
...
],
"download": [
{
"quality": "다운로드 파일 화질",
"type": "파일 타입",
"width": 파일 가로,
"height": 파일 세로,
"expires": "만료일시",
"link": "다운로드 다이렉트 링크",
"created_time": "생성일시",
"fps": 주사율,
"size": 파일 크기,
"md5": "토큰"
},
...
],
"app": {
"name": "앱 이름",
"uri": "앱 링크"
},
"status": "영상 상태",
"resource_key": "리소스 키",
"embed_presets": null
}

여담

API의 내부 구조는 헤더추가와 curl로만 이루어져있다. OAuth2.0과 RESTful를 이해했다면 아주 쉬울 것이다.

Vimeo Upload API - 1. Vimeo Developers

· 약 4분

비메오 개발자 커뮤니티 로그인 후 MyApps > Create New App 버튼을 클릭한다. image from hexo 사용할 앱의 이름, 설명, URL 경로와 앱 로고 URL을 등록한다. App Callback URL은 하나의 계정안에 멀티 유저를 두고 각자의 유저명으로 여러 동영상을 등록할시 OAuth2.0 인증을 통해 인증을 받기위한 것인데, 단순한 업로드 로직일 경우에는 필요가 없다. 앱에서 업로드가 있는 폴더안으로 경로만 대충 잡아주면 된다.

권한 신청

생성된 앱으로 들어가 Request Upload Access를 클릭한다. image from hexo image from hexo 1번은 이 앱(test)에 요금을 받을 것인지를 묻는다. Yes 클릭시 비메오측 승인이 없으면 요금청구를 할 수 없다는 경고문과 함께 어떻게 차징을 할지 이유를 쓰는 란이 생긴다. 업로드로 과금을 받진 않을 것이니 No를 선택하자.

2번은 업로더의 계정으로 업로드를 할 것인지, 내 계정으로만 업로드를 할 것인지를 선택한다. 전자를 선택시에 Callback URL을 필히 설정해주어야하고 Callback URL에 Return된 Multi-User의 Access Token을 가지고 분기 업로드를 해주는 로직을 구현해야 한다. 하지만 우리는 한가지 계정에서의 비디오 업로드를 구현하기에 후자를 선택하면 된다.

My account 선택시 비디오의 제작자를 묻는 선택지가 나오는데 선택해준다.

3번은 어떤 종류에 대한 비디오가 업로드가 될지 영문으로 설명을 해야한다. 간단히 "test용이다" 라고 적으니 Reject메일이 날라오는 걸로 보아 구체적으로 적어야한다. 샘플 동영상을 링크 걸어주는게 가장 간단한 인증방법이 될 것이다.

Request Upload Access를 클릭하면 5영업일 내에 처리해주겠다는 상태가 된다. image from hexo

토큰 생성

생성된 앱에서 Authentication 메뉴로 들어가 scope를 설정하고 Generate Token 버튼을 클릭한다. image from hexo Create는 채널을 만드는거라 필요없고 Edit, Delete, Upload 권한정도를 설정하면 된다.

image from hexo Access Token, Client Identifier, Client Secret를 모두 저장해둔다. Access Token은 분실시 다시 확인할 수 없고, 재발급만 가능하니 잘 간직하자.

회신 기다리기

회원가입시 등록한 메일 주소로 Vimeo 측에서 Upload Access에 대한 회신메일이 온다. Reject시 상세한 이유가 Approved시 환영한다라는 내용이다. 조건을 충족해 승인 완료가 되어 해당 앱에 다시 들어가보면 아래처럼 상태가 바뀐다. image from hexo

2. PHP API 사용으로 이어집니다.

XML-RPC를 활용한 네이버 블로그 글쓰기 API

· 약 2분

OAuth 를 이용한 블로그 API 가 있는데, 네이버 블로그 글쓰기는 그보다 더 간단히 구현할 수 있다.

XML-RPC에서 다운받는다. image from hexo

압출을 푼 뒤 lib/xmlrpc.inc 파일을 로직을 만들 곳에 복사해 놓는다.

네이버 블로그 플러그인 설정

관리 > 글쓰기 API 설정 메뉴로 들어간다. image from hexo

사용하기로 설정을 바꾼 후 비밀번호를 기억하고, 어디에 등록할지 카테고리를 정한다. image from hexo

API 연동

<?php

include_once "xmlrpc.inc";

$title = $_POST['title'];
$content = $_POST['content'];
$result = newPost($title, $content);

echo json_encode($result);
// 블로그 API 함수
function newPost($title, $description) {
$g_blog_url = "https://api.blog.naver.com/xmlrpc";
$user_id = "아이디";
$blogid = "아이디";
$password = "발급받은 비밀번호";
$publish = true;
$client = new xmlrpc_client($g_blog_url);
$client->setSSLVerifyPeer(false);

$GLOBALS['xmlrpc_internalencoding'] = 'UTF-8';

$struct = [
'title' => new xmlrpcval($title, "string"),
'description' => new xmlrpcval($description, "string")
];

$f = new xmlrpcmsg("metaWeblog.newPost",
[
new xmlrpcval($blogid, "string"),
new xmlrpcval($user_id, "string"),
new xmlrpcval($password, "string"),
new xmlrpcval($struct , "struct"),
new xmlrpcval($publish, "boolean")
]
);

$f->request_charset_encoding = 'UTF-8';
return $response = $client->send($f);
}
?>

네이버 블로그는 html 태그가 먹으므로 escape 처리를 할 필요는 없다.

RESTful을 위한 PHP HTTP Method 처리

· 약 1분

메소드를 분기해서 새로운 배열에 담아주면 된다.

contentType을 application/json으로 보냈을 경우

<?
$method = strtolower($_SERVER['REQUEST_METHOD']);
switch ($method) {
case 'get':
$input = json_decode(json_encode($_GET), true);
break;
case 'post':
$input = json_decode(file_get_contents('php://input'), true);
break;
case 'put':
$input = json_decode(file_get_contents('php://input'), true);
break;
case 'delete':
$input = json_decode(file_get_contents('php://input'), true);
break;
}
?>

contentType을 그냥 전송한다면 **file_get_contents('php://input')**으로 받으면 된다.

여담

GET을 제외한 method는 params를 JSON.stringify한 뒤에 file_get_contents로 읽어오면 되는데, GET으로는 file전송을 할 수 없기 때문에 위처럼 받으면 된다.

550 : smtp auth address is not same to envfrom address (#5.5.0)

· 약 1분

stmp 로 메일 발송시 아래와 같은 오류가 발생하는 경우가 있다.

550 : smtp auth address is not same to envfrom address (#5.5.0)
The following From address failed: [email protected] : MAIL FROM command failed, smtp auth address is not same to envfrom address (#5.5.0)

해결

smtp 인증 username 과 보내는 메일주소가 같지 않아서 발생한다. username 과 from email 을 일치시켜주면 해결된다.