안녕하세요.

원래 수줍어서 이런거 못올립니다만 .

다른분들이 해결방법을 찾으셧으면 해서 올립니다 .



전 img 및 script rpc 를 이용하여 값을 넘길때.

해당 페이지 or 받는 페이지가 utf-8 이면

받는페이지에서


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

// 값이 아래와 같다면
$a = "http://comefeel.com/tt/comefeel/entry/윈도우XP-속도-200-빠르게-하기?info=nom&elch=18";

$b = parse_url($a);
echo "<pre>";
print_r($b);

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

위와같이 한다면 한글 부분이 깨져서 나옵니다.
정확한 인코딩도 다 해봤으나 유효 불가해서 아래와 같이
그냥 -_- 무식하게 (parse_url 처럼 혹은 비슷 ) 나눠 봤습니다.

좀더 좋은 팁이 있거나 좋은거 알고계신분은 정보 공유 합시다.


======================================

// 값이 아래와 같다면
$a = "http://comefeel.com/tt/comefeel/entry/윈도우XP-속도-200-빠르게-하기?info=nom&elch=18";

preg_match('@(^.*):\/\/(.*?)/([^?]*)\??(.*)@', $a, $matches);

 echo "<pre>";
 var_dump( ($matches) );

=======================================
2008/07/11 19:27 2008/07/11 19:27
저 렴한 광랜의 등장과 대용량 하드디스크 가격의 하락, 그리고 Adobe 사의 플래시 플레이어(Flash Player), 플래시 비디오(Flash Video)의 등장으로 인터넷을 통한 비디오 공유가 정말 많이 보편화 되었습니다. 구글 비디오(http://video.google.com)와 YouTube(http://www.youtube.com)가 이미 이런 비디오 사업을 시작한지 오래됐지만, 여전히 공략할 수 있는 틈새 시장이 굉장히 많이 있다고 할 수 있는데, 그럼 우리도 한 번 틈새 시장을 공략해 보면 어떨까? PHP, 플래시, Adobe의 Flex를 이용해서 어떻게 하면 비디오 공유 사이트를 만들 수 있을까? 사실 알고보면 정말 쉽게 만들 수 있습니다.

여기서는 PHP를 이용해서 웹 사이트를 만드는 방법 그리고 Flex를 이용해서 Flash로 된 비디오 뷰어를 만드는 방법에 대해서 설명을 하겠습니다. 그럼 먼저 더 진행하기 전에 준비해야 하는 소프트웨어 몇 가지를 살펴보도록 하죠.

우선 서버쪽에서는 PHP와 MySQL이 필요합니다. MySQL은 비디오에 대한 정보(예를 들면, 비디오의 파일 이름, 미리보기 파일, 미리보기 파일의 너비와 높이, 제목, 그리고 기타 정보 등)를 저장하는데 사용되겠습니다. PHP는 전체적인 페이지를 구성하는데 사용되게 됩니다.

그리고 ffmpeg(http://ffmpeg.mplayerhq.hu/) 이라고 하는 유틸리티 프로그램도 필요한데요, 이 프로그램은 유저가 올리는 비디오 파일을 플래시 비디오 파일(FLV)로 변환하는 역할을 수행하게 됩니다. ffmpeg은 비디오의 변환외에도 비디오의 스냅샷을 찍어서 미리보기 파일을 만들어 낼 수도 있습니다. 이 ffmpeg을 이용하게 되면 사실상 어려운 작업을 손쉽게 처리할 수가 있어서 우리가 MyTube를 구현하는데 상당히 유용하게 활용이 됩니다.

클라이언트쪽에서는 두 가지 방법이 있는데요. 하나는 YouTube에서와 같이 HTML과 Flash를 같이 이용해서 인터페이스를 구성하는 방법이 있고, 두 번째로 플래시만으로 인터페이스를 구성하는 방법이 있습니다. 이 글에서는 Flex 프레임워크를 이용해서 비디오를 보고 등록된 비디오를 탐색하고 찾기 위해서 리스트를 생성하도록 할 예정입니다.

PHP로 서버쪽 코드 구성하기

서버쪽 코드 작성을 하기에 앞서, MySQL에 데이터 스키마를 생성해야 합니다. 우선 사용할 데이터베이스를 생성하기 위해서, 다음과 같이 mysqladmin 명령어를 사용합니다.
mysqladmin create movies 
스키마가 생성되었으면 데이터베이스를 로드합니다. 스키마 파일은 아래 [리스트 1]과 같습니다.

[리스트 1] movies.sql
DROP TABLE IF EXISTS movies; 
CREATE TABLE movies (
movieId INTEGER NOT NULL AUTO_INCREMENT,
title VARCHAR( 255 ),
source VARCHAR( 255 ),
thumb VARCHAR( 255 ),
width INTEGER,
height INTEGER,
PRIMARY KEY( movieId )
);
이제 위의 movies.sql 스키마 파일을 다음과 같은 명령어를 이용해서 데이터베이스에 테이블을 생성할 수 있습니다.
mysql movies < movies.sql 
데이터베이스에 무비 데이터를 넣기 위해서는 HTML을 이용해서 업로드 기능을 만들어야 합니다. 즉 비디오 파일을 받아서 플래시 비디오 파일로 변환하고 미리보기 파일을 만든후에 데이터베이스에 넣으면 되겠습니다.

업로드 페이지의 제작

비디오 파일을 업로드 하기 위한 HTML 파일은 다음 [리스트 2]에서 보는 것과 같이 아주 간단합니다.

[리스트 2] addmovie.html
<html>
<body>
<form enctype="multipart/form-data" method="post" action="upload.php">
<input type="hidden" name="MAX_FILE_SIZE" value="300000" />
<table>
<tr><td>Title</td><td><input type="text" name="title"></td></tr>
<tr><td>Movie</td><td><input type="file" name="movie"></td></tr>
</table>
<input type="submit" value="Upload" />
</form>
</body>
</html>
위 HTML은 입력받은 정보를 upload.php 페이지로 전송하게 되는데, 이 페이지에서 비디오를 변환하고 미리보기를 만들어 내고 데이터베이스에 저장하게 되는 것입니다. 다음의 upload.php 코드를 보도록 하겠습니다.

[리스트 3] upload.php
<html><body>
<?php
require "DB.php";

function converttoflv( $in, $out )
{
unlink( $out );
$cmd = "ffmpeg -v 0 -i $in -ar 11025 $out 2>&1";
$fh = popen( $cmd, "r" );
while( fgets( $fh ) ) { }
pclose( $fh );
}

function getthumbnail( $in, $out )
{
unlink( $out );
$cmd = "ffmpeg -i $in -pix_fmt rgb24 -vframes 1 -s 300x200 $out 2>&1";
$fh = popen( $cmd, "r" );
while( fgets( $fh ) ) { }
pclose( $fh );
}

function flv_import( $upfile, $fname, $title )
{
$fname = preg_replace( '/..*$/', '', basename( $fname ) );
$flvpath = "$fname.flv";
$thumbpath = "$fname.gif";

converttoflv( $upfile, "movies\$flvpath" );
getthumbnail( $upfile, "movies\$thumbpath" );

$dsn = 'mysql://root@localhost/movies';
$db =& DB::connect( $dsn );
if ( PEAR::isError( $db ) ) { die($db->getMessage()); }

$sth = $db->prepare( 'INSERT INTO movies VALUES ( 0, ?, ?, ?, ?, ? )' );
$db->execute( $sth, array( $title, $flvpath, $thumbpath, 300, 200 ) );
}

flv_import( $_FILES['movie']['tmp_name'], $_FILES['movie']['name'], $_POST['title'] );
?>
File sucessfully uploaded
</body></html>
위 코드에서 flv_import 함수를 중점적으로 봐야 합니다. flv_import 함수내에서 converttoflv 함수로 비디오 파일을 플래시 비디오 파일로 변경하고 있고, getthumbnail 함수로 미리보기 파일을 생성하고 있습니다. 그리고 다음으로 업로드가 완료된 무비에 대한 정보를 데이터베이스에 저장합니다. 위 리스트 3에 있는 FLV 플래시 비디오 파일과 미리보기 파일을 생성하는 함수는 ffmpeg 라는 명령어와 여러가지 명령어를 이용해서 변환을 수행하게 됩니다.

그럼 다음 [그림 1]처럼 addmovie.html 페이지를 브라우저로 한 번 보도록 하겠습니다.


[그림 1] 비디오를 업로드하는 페이지

여기서 비디오 파일을 지정하고 Upload 버튼을 눌러서 비디오 파일을 처리하기 위해 서버에 보낼 수가 있습니다.

사 실 upload.php 파일은 아주 기본적인 부분만 작성이 되어 있기때문에, 실제 서비스 용도로 사용하기 위해서는 에러 체크 루틴을 추가 적으로 작성해야 합니다. 그리고 그것보다도 더 큰 문제는 크기가 큰 비디오 파일을 업로드 하려고 할 때인데, 이런 경우에는 파일의 크기가 크기 때문에 비디오 변환 과정이 오래 걸리게 되고 유저의 대기시간이 상당히 길어지면서 더 큰 문제가 됩니다.

그럼 이런 문제를 해결하기 위한 방법은 뭐가 있을까요? 한 가지 방법으로 큰 크기의 비디오 파일이 업로드가 되면(10초 이상의 비디오 파일) 유저에게는 잠시 후에 비디오가 게시될 것이라고 말을 해 놓고 서버내의 다른 폴더에 비디오 파일을 저장한 후에 또 다른 스크립트를 이용해서 비디오를 변환하는 것입니다.

더 진행하기 전에 왜 꼭 플래시 비디오 파일로 변환을 해야 하는지에 대해서 생각을 해보도록 합시다. 그냥 원본 그대로 저장해도 되는데 왜 플래시 비디오로 변환을 하려고 하는 걸까요? 그건 원본 상태로 저장을 해 놓게 되면 각 비디오 파일의 타입 별로 비디오 플레이어를 찾아서 수행할 수 있는 코드를 작성을 해야만 하기 때문에, 굉장히 힘든 일이 될 것이라고 생각합니다.

이 과정을 플래시 파일로 변환하여 해결하게 되면 코드도 간단해지고 많은 OS에서 실행될 수 있도록 할 수도 있습니다.

그럼 이제 HTML과 플래시를 이용해서 유투브와 같은 입력양식을 간단하게 만들어 보겠습니다.

HTML과 플래시를 이용한 인터페이스 구성

입 력받은 URL을 가지고 플래시 비디오 파일을 재생하는 프로그램을 만들기 위해서는 Adobe Flex Builder 2를 이용해서 새로운 프로젝트를 만들어야 합니다. 새로운 프로젝트를 생성했다면 simplemovie.mxml 이라는 Flex 애플리케이션을 만들어야 합니다. 이 애플리케이션 파일의 내용은 다음 [리스트 4]와 같습니다.

[리스트 4] simplemovie.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:VBox backgroundColor="white" width="400" height="335">
<mx:VideoDisplay width="400" height="300" id="videoPlayer"
source="{Application.application.parameters.movie}" />
<mx:HBox width="100%" horizontalAlign="center">
<mx:Button label="Play" click="videoPlayer.play()" />
</mx:HBox>
</mx:VBox>
</mx:Application>
위 [리스트 4]에서 두가지 중요한 요소를 볼 수 있습니다 : VideoDisplay 요소는 비디오를 재생하는 역할을 하고 "Play"라는 이름을 가진 버튼은 비디오의 재생이 끝난 후에 유저가 클릭할 경우 비디오를 다시 재생하는 역할을 하게 됩니다.

VideoDisplay 요소는 "source"라는 속성을 가지게 되는데요, source 속성으로 재생해야 하는 플래시 비디오 파일의 URL을 지정하게 됩니다. 위 리스트에서 source 속성이 가지고 있는 값은 HTML 파일에 있는 <object>나 <embed> 태그에 있는 FlashVars 속성의 값이 되게 됩니다.

Flex Builder를 이용하게 되면 위 [리스트 4]의 simplemovie.mxml 프로그램을 simplemovie.swf 파일로 변환할 수가 있고, 변환된 swf 파일을 bin 디렉토리에서 PHP가 있는 곳의 디렉토리로 이동시켜야 합니다. 그리고 PHP 페이지를 하나 만들어서 비디오를 재생시킬 수가 있습니다. 다음 [리스트 5]를 보도록 하죠.

[리스트 5] simpletest.php
<?php
require "DB.php";

$moviebase = 'http://localhost:8080/movies/';

$dsn = 'mysql://root@localhost/movies';
$db =& DB::connect( $dsn );
if ( PEAR::isError( $db ) ) { die($db->getMessage()); }

$source = null;
$movieId = 1;
if ( array_key_exists( 'movie', $_GET ) )
$movieId = $_GET['movie'];

$movies = array();
$res = $db->query( 'SELECT movieId, source, title FROM movies' );
while( $row = $res->fetchrow( ) ) {
$movies []= $row;
if ( $row[0] == $movieId )
$source = $row[1];
}

if ( $source == null )
$source = $movies[0][1];
?>
<html>
<body>
<table>
<tr><td valign="top">
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="400"
height="335"
codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
<param name="movie" value="simplemovie.swf" />
<param name="quality" value="high" />
<param name="flashVars" value="movie=<?php echo( $moviebase.$source ) ?>">
<embed src="simplemovie.swf" quality="high"
width="400" height="335" play="true"
loop="false"
quality="high"
flashVars="movie=<?php echo( $moviebase.$source ) ?>"
type="application/x-shockwave-flash"
pluginspage="http://www.adobe.com/go/getflashplayer">
</embed>
</object>
</td><td valign="top">
<?php
foreach( $movies as $movie ) {
?>
<a href="simptest.php?movie=<?php echo( $movie[0] )?>"><?php echo( $movie[2] )?></a><br/>
<?php
}
?>
</td></tr></table>
</body>
</html>
위 PHP 스크립트는 우선 데이터베이스에 접속한 후에 비디오 리스트를 받아오고 있습니다. 그리고 나서 URL을 통해서 넘어온 ID와 읽어온 비디오 리스트를 비교해서 동일한 ID를 가진 비디오가 있는지를 확인하게 됩니다. 동일한 ID를 찾을 경우 이 ID 값을 simplemovie.swf 파일로 넘기기 위해서 flashVars 속성에 지정하고 있습니다.

PHP 스크립트 다음 부분에서는 HTML 태그가 시작되고 simplemovie.swf 파일을 페이지에 표시하기 위한 태그인 <object>, <embed> 태그를 사용하고 있습니다. 물론 여기에 재생해야 하는 비디오에 대한 URL도 지정해 주고 있는 걸 볼 수 있습니다. 그리고 바로 아래에 현재 비디오외에 볼 수 있는 비디오에 대한 링크를 만들어 주고 있는 걸 볼 수 있습니다.

이제 웹 브라우저에서 [리스트 5]에 있는 페이지를 한 번 보도록 하겠습니다. 다음 [그림 2]와 같이 나오네요.


[그림 2] 간단한 비디오 플레이어와 함께 볼 수 있는 비디오에 대한 리스트가 출력되었다.

웹 브라우저를 열자마자 첫번째 비디오가 재생이 되게 되고, 오른쪽에 있는 비디오 리스트중에서 하나를 선택하면 페이지가 다시 로딩되면서 선택된 비디오가 재생되게 됩니다.

정말 간단하죠? Flex 파일 하나와 PHP 파일 하나, 그리고 데이터베이스만 가지고 위와 같이 비디오 공유 사이트를 만들었습니다.




Flex를 이용한 인터페이스 구성 파트 1


Flex 를 이용해서 원하는 비디오를 재생시키기 위해서는 Flex에게 재생시킬 수 있는 비디오의 리스트를 알려줘야만 합니다. 어떻게 해야하냐면 XML파일을 이용해서 Flex에게 비디오 리스트 정보를 넘겨줄 수가 있는데요, 여기서는 PHP로 다시 돌아가서 데이터베이스에서 비디오 리스트를 읽어들인 후에 XML로 출력하는 스크립트를 만들어 보도록 하겠습니다. 다음 [리스트 6]의 movies.php 파일을 보도록 하죠.

[리스트 6] movies.php
<?php
require "DB.php";

$moviebase = 'http://localhost:8080/movies/';

header( 'content-type: text/xml' );

$dsn = 'mysql://root@localhost/movies';
$db =& DB::connect( $dsn );
if ( PEAR::isError( $db ) ) { die($db->getMessage()); }
?>
<movies>
<?php
$res = $db->query( 'SELECT title, source, thumb, width, height FROM movies' );
while( $row = $res->fetchrow( ) ) {
?>
<movie title="<?php echo( $row[0] ) ?>" source="<?php echo( $moviebase.$row[1] ) ?>"
thumb="<?php echo( $moviebase.$row[2] ) ?>" width="<?php echo( $row[3] ) ?>"
height="<?php echo( $row[4] ) ?>" />
<?php
}
?>
</movies>
위 PHP 스크립트를 만든 후에 커맨드 라인에서 실행시키거나 브라우저에서 실행시키게 되면 다음 [그림 3]과 같은 XML 리스트를 볼 수가 있습니다.


[그림 3] XML로 표현된 비디오 리스트

이제 XML로 비디오 리스트 정보를 넘겨줄 수 있으니 전에 만들었던 simplemovie.mxml 파일을 좀 더 개선해 보도록 하겠습니다. 다음 [리스트 7]은 simplemovie.mxml의 업그레이드 된 버전입니다.

[리스트 7] mytube1.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" creationComplete="movieXmlData.send()">

<mx:HTTPService method="get" url="http://localhost:8080/movies.php"
id="movieXmlData" result="onGetMovies( event )" />

<mx:Script>
import mx.rpc.events.ResultEvent;
import mx.controls.VideoDisplay;
import mx.controls.List;
import mx.rpc.http.HTTPService;
import mx.collections.ArrayCollection;

[Bindable]
private var movies : ArrayCollection = new ArrayCollection();

public function onGetMovies( event : ResultEvent ) : void
{
var firstMovie : String = event.result.movies.movie[0].source.toString();
videoPlayer.source = firstMovie;

movies = event.result.movies.movie;
movieList.selectedIndex = 0;
}

public function onPrevious() : void
{
if ( movieList.selectedIndex == 0 )
movieList.selectedIndex = movies.length - 1;
else
movieList.selectedIndex -= 1;
videoPlayer.source = this.movieList.selectedItem.source.toString();
}

public function onPlay() : void
{
videoPlayer.source = this.movieList.selectedItem.source.toString();
videoPlayer.play();
}

public function onNext() : void
{
if ( movieList.selectedIndex >= ( movies.length - 1 ) )
movieList.selectedIndex = 0;
else
movieList.selectedIndex += 1;
videoPlayer.source = this.movieList.selectedItem.source.toString();
}

public function onChange() : void
{
videoPlayer.source = this.movieList.selectedItem.source.toString();
}
</mx:Script>

<mx:HBox width="100%" paddingLeft="10" paddingTop="10" paddingRight="10">
<mx:VBox>
<mx:VideoDisplay width="400" height="300" id="videoPlayer" complete="onNext()" />
<mx:HBox width="100%" horizontalAlign="center">
<mx:Button label="<<" click="onPrevious()" />
<mx:Button label="Play" click="onPlay()" />
<mx:Button label=">>" click="onNext()" />
</mx:HBox>
</mx:VBox>
<mx:List width="100%" height="340" id="movieList"
dataProvider="{movies}"
change="onChange()"
labelField="title"></mx:List>
</mx:HBox>

</mx:Application>
전과 비교해서 크게 바뀐 부분이 있다면 파일의 상단에 있는 액션 스크립트(ActionScript)인데요, 이 코드로 전체적인 인터페이스를 관리하게 됩니다. 이 액션 스크립트가 하는 일은 먼저 onGetMovies 함수에 있는 HTTPService를 이용해서 movies.php 파일로부터 XML 정보를 읽어들이는 것입니다. HTTPService 클래스는 XML 리스트를 찾게 되면 XML 문서 객체모델(Document Object Model)로 변경하게 되고, 우린 이 문서 객체 모델을 이용해서 첫번째 비디오에 대한 정보를 얻어서 재생할 수가 있습니다. 또 onGetMovies 함수는 movies 라는 변수를 이용해서 페이지에 있는 리스트 박스에 비디오의 이름을 출력하게 됩니다. 나머지 액션 스크립트는 유저가 리스트 박스에 있는 비디오를 선택하거나 "이전", "다음" 버튼을 선택했을 경우를 처리하기 위한 코드입니다.

위 리스트의 제일 아래를 보면 전체 유저 인터페이스를 구성하는 Flex 오브젝트를 볼 수 있습니다. 여기에 이전 비디오와 다음 비디오를 선택할 수 있는 버튼을 배치하고, 오른쪽에는 현재 비디오 리스트를 출력하는 리스트 박스가 배치되어 있습니다.

이제 Flex Builder를 이용해서 위 프로그램을 컴파일하고 실행시키게 되면 [그림 4]와 같은 화면을 볼 수 있습니다.


[그림 4] Flex를 이용해서 구성한 첫 번째 인터페이스

리스트 박스에서 비디오를 선택할 수도 있고, 이전, 다음 버튼을 이용해서 비디오를 선택할 수도 있습니다. 멋있죠? 이제 미리보기 이미지를 제공해 주면 더 멋있어질 것 같네요.

Flex를 이용한 인터페이스 구성 파트 2 – 미리보기 이미지

미 리보기 이미지를 비디오 리스트에 출력하려면 리스트 박스를 비디오의 제목과 미리보기 이미지를 같이 출력할 수 있도록 수정해야 합니다. 다행히도 Flex의 기능을 이용하면 아주 쉽게 수정이 가능합니다. 우선 <List> 태그에 itemRenderer를 추가하도록 하고, 다음 [리스트 8]을 보겠습니다.

[리스트 8] mytube2.mxml
...
<mx:List width="100%" height="340" id="movieList"
dataProvider="{movies}"
change="onChange()"
itemRenderer="MovieItem"></mx:List>
...
여기서 MovieItem이라는 item renderer MXML 컴포넌트를 만들었습니다. 이 컴포넌트를 만들려면 메뉴에서 "New > MXML Component"를 선택하고 [리스트 9]와 같이 컴포넌트를 코드에 넣으면 됩니다.

[리스트 9] MovieItem.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" height="80">
<mx:Image source="{data.thumb}" width="{data.width/3}"
height="{data.height/3}" rotation="5" left="10" top="0" />
<mx:Label text="{data.title}" fontWeight="bold" top="10" left="100" fontSize="18" />
</mx:Canvas>
여기서는 Canvas 라는 컨테이너를 이용했지만, 원한다면 마음에 드는 컨테이너를 선택해서 설정하셔도 괜찮습니다. 그리고 나서 미리보기 이미지 추가를 위해서 <mx:Image> 태그를 사용하고 비디오 제목을 출력하기 위해서 <mx:Label>을 이용하면 됩니다. 좀 더 재밌게 해보기 위해서 미리보기 이미지를 약간 회전시켜 봤습니다. [그림 5]를 보도록 하죠.


[그림 5] 미리보기 이미지를 추가한 리스트 박스

꽤 괜찮은 비디오 플레이어가 됐네요. 여기에 추가적으로 비디오 설명, 재생 시간, 링크, 추천 버튼과 같은 기능을 추가하면 더 좋을 것 같습니다.

저장소와 대역폭

데 이터베이스를 구성하고 비디오 공유 사이트 페이지를 만들어 내는것 자체는 지금까지 잘 해결했는데, 사실 이것말고 한가지 더 고려해야 할 것이 있습니다. 바로 대역폭을 고려해야 합니다. 플래시 비디오 파일 자체가 인코딩이 잘 된다고 해도 역시 비디오 파일이기 때문에 크기가 큰 편에 속하게 됩니다. 그렇기 때문에 중간에 끊김없이 비디오 재생을 얼마나 할 수 있는지 파악하는 것이 무엇보다 중요하게 됩니다.

확실한 방법중 하나는 인터넷 데이터 센타에서 서비스를 하는 것입니다. 다른 방법으로는 비디오 공유 사이트에서는 비디오 자체에 대한 데이터를 가지지 않고 링크만 저장하고 실제 비디오 데이터는 다른 곳에 저장하는 방법입니다. 아마존의 S3 서비스 같은 경우가 좋은예인데요, 저렴한 가격으로 좋은 저장소로 활용할 수가 있고, 어느정도 사이트가 커질때까지는 안정적으로 활용할 수 있습니다.

결론

플래시를 이용한 비디오의 등장과 광대역폭의 보편화로 인해서 이제 적은 예산으로 비디오 공유 사이트를 운영한다는 것이 현실로 다가왔습니다. 바라기는 이 글을 통해서 여러분이 좀 더 멋있는 비디오 공유사이트를 만들어냈으면 하는 것입니다.
2007/12/26 16:16 2007/12/26 16:16
New Object Model

PHP 5 에는 새로운 객체 모델이 존재한다. PHP의 객체 조작사항은 더 나은 성능과 보다 많은 특징을 위해 완벽하게 재작성되었다. PHP이전 버전에서 객체는 원시적인 형태로 조작되었다. ( 실례를 들자면 정수나 문자열 같은 것들을 말이다. ). 이 객체 안의 메소드가 가진 결점은 의미론적으로, 어떤 변수가 할당되었거나 파라미터의 값을 메소드로 전달할 때 모든 객체들이 복제된다는 것이었다. 이제 새로운 접근방식에서는 객체가 핸들에 의해 참조되고 값으로 참조되지 않는다. ( 객체식별자와 같은 핸들로 생각할 수 있을 것이다 ).

   많은 PHP 프로그래머들은 심지어는 과거의 객체모델이 멋대로 복제되는 것을 눈치채지 못했고 그랬기때문에 PHP어플리케이션의 대부분은 아주 좁은 틀을 벗어나 동작했을 것이다. 


Private and Protected Members

PHP 5 는 클래스 프로퍼티의 가시성( 可視性 : visibility )을 정의할 수 있게 하는 private 와 protected 멤버 변수를 도입했다.


Example B-4. Private and Protected Members accesibility

Protected 멤버 변수는 확장된 클래스에서 중복 선언되면 접근할 수 있는데 비해, private 멤버 변수는 단지 멤버 변수를 소유한 클래스에서만 접근이 가능하다.

<?php
class MyClass
{
  
private $Hello = "Hello, World!\n"
;
  
protected $Bar = "Hello, Foo!\n"
;
  
protected $Foo = "Hello, Bar!\n"
;

   function
printHello
() {
       print
"MyClass::printHello() " . $this->Hello
;
       print
"MyClass::printHello() " . $this->Bar
;
       print
"MyClass::printHello() " . $this->Foo
;
   }
}

class
MyClass2 extends MyClass
{
  
protected $Foo
;
            
   function
printHello
() {
      
MyClass::printHello();                         
/* Should print */
      
print "MyClass2::printHello() " . $this->Hello;
/* Shouldn't print out anything */
      
print "MyClass2::printHello() " . $this->Bar
/* Shouldn't print (not declared)*/
      
print "MyClass2::printHello() " . $this->Foo
/* Should print */
  
}
}

$obj = new MyClass
();
print
$obj->Hello
/* Shouldn't print out anything */
print $obj->Bar;   
/* Shouldn't print out anything */
print $obj->Foo;   
/* Shouldn't print out anything */
$obj->printHello();
/* Should print */

$obj = new MyClass2
();
print
$obj->Hello
/* Shouldn't print out anything */
print $obj->Bar;   
/* Shouldn't print out anything */
print $obj->Foo;   
/* Shouldn't print out anything */
$obj->printHello
();
?>
 
 

PHP 5에서는 또한 private 와 protected 메소드가 도입되었다.


Example B-5. Protected methods example

<?php
class Foo
{
  
private function aPrivateMethod
() {
       echo
"Foo::aPrivateMethod() called.\n"
;
   }

  
protected function aProtectedMethod
() {
       echo
"Foo::aProtectedMethod() called.\n"
;
      
$this->aPrivateMethod
();
   }
}

class
Bar extends Foo
{
  
public function aPublicMethod
() {
       echo
"Bar::aPublicMethod() called.\n"
;
      
$this->aProtectedMethod
();
   }
}

$o = new Bar
;
$o->aPublicMethod
();
?>

과거의 코드에서는 사용자 정의된 클래스나 함수가 "public", "protected" 또는 "private"를 명기하지 않고 실행했을 것이다.


Abstract Classes and Methods

PHP 5는 또한 추상클래스라는 것과 추상메소드라는 것이 도입되었다. 추상메소드는 단지 메소드의 특징적인 사항을 선언하고 수행사항을 제공하지는 않는다. 다음 예시에서 클래스는 abstract로 선언하는 것을 필요로 하는 추상 메소드를 포함한다.


Example B-6. Abstract class example

<?php
abstract
class AbstractClass
{
  
abstract public function test
();
}

class
ImplementedClass extends AbstractClass
{
  
public function test
() {
       echo
"ImplementedClass::test() called.\n"
;
   }
}

$o = new ImplementedClass
;
$o->test
();
?>

요약클래스는 명시화될 수 없다. 과거의 코드에서는 사용자 정의된 클래스나 함수에 "abstract"를 명기하지 않고 실행했을 것이다.


Interfaces

PHP 5 에서 interface라는 새로운 객체지향 개념이 도입되었다. 클래스는 인터페이스의 임의의 목록을 수단으로 삼을 것이다.


Example B-7. Interface example

<?php
interface Throwable
{
  
public function getMessage
();
}

class
MyException implements Throwable
{
  
public function getMessage
() {
      
// ...
  
}
}
?>

과거에는 사용자정의된 클래스나 함수에 "interface"나 "implements"를 붙이지 않고 실행했을 것이다.


Class Type Hints

 느슨한 유형이 남아있는 PHP5는 클래스 타입 힌트를 사용하여 파라미터로부터 메소드로 값을 전달하는 개체의 요청된 클래스를 선언하는 능력을 도입하였다.


Example B-8. Class type hinting example

<?php
interface Foo
{
   function
a(Foo $foo
);
}

interface Bar
{
   function
b(Bar $bar
);
}

class
FooBar implements Foo, Bar
{
   function
a(Foo $foo
) {
      
// ...
  
}

   function
b(Bar $bar
) {
      
// ...
  
}
}

$a = new FooBar
;
$b = new FooBar
;

$a->a($b
);
$a->b($b
);
?>

이러한 클래스 타입 힌트는 보통 유형화된 언어에서와 같이 컴파일 할 때에는 체크하지 않는다. 그러나 실행 도중에 체크한다. 이것은 다음을 의미한다:

<?php
function foo(ClassName $object
) {
  
// ...
}
?>


는 다음과 같다 :

<?php
function foo($object
) {
   if (!(
$object instanceof ClassName
)) {
       die(
"Argument 1 must be an instance of ClassName"
);
   }
}
?>
 

PHP 5 는 최종 멤버와 메소드를 선언하기 위해 "final" 키워드를 도입하였다. final을 붙인 메소드와 멤버는 하위클레스에 의해 오버라이드 되지 않는다.


Example B-9. final method

<?php
class Foo
{
  
final function bar
() {
      
// ...
  
}
}
?>

이것은 더군다나 최종적인 클래스를 만드는데 가능하다. 이것은 클래스가 특별화 되는 것을 막는다. (다른 클래스에 의해 '절대' 상속될 수 없다.). final 클래스는 자신들의 메소드를 final 로 선언할 필요가 없다.


Example B-10. final class

<?php
final
class Foo
{
  
// class definition
}

// the next line is impossible
// class Bork extends Foo {}
?>

프로퍼티는 final 속성을 가질 수 없다..

과거에는 사용자정의된 클래스나 함수에 "final"을 붙이지 않고 실행했을 것이다.


Objects Cloning

   PHP 4 에서는 객체가 복제되었을 때 복제된 생성자를 실행하기 위한 결정을 사용자가 할 수 없는 그런 방법을 제공했었다. 복제하는 동안에는 PHP 4 에서는 모든 객체의 프로퍼티에 대한 이상적 복제물을 만들기 위해 비트복사를 하는 단역을 수행하였다.  

   전체적으로 복제된 프로퍼티와 함께 복제된 객체를 만드는 것은 항상 원하는 행동이 아니다. 생성자 복제를 위해 필요한 것에 대한 좋은 예는 만약 GTK 윈도우를 묘사하는 객체를 소유하고 있고 객체는 이 객체를 복제할때의 GTK 윈도우의 리소스로 유지될 때, 아마 같은 프로퍼티를 가진 새로운 윈도우를 생성하길 원할것이고 새 윈도우의 리소스를 새 객체가 포함하길 원할 것이다. 다른 예로는 만약 객체가 다른 객체를 사용하는 참조자를 붙들어매고 있고, 개발자는 부모객체를 복제할때, 이 다른 객체의 새로운 인스턴스를 생성하길 원할 것이고 그래서 복제된 개체는 그 자신의 분산된 복제물을 가지고 있을 것이다.

복제되는 객체는 clone 키워드를 사용하여 생성된다. ( 가능하다면 객체의 __clone() 메소드를 호출한다 ). 객체의 __clone() 메소드는 직접적으로 호출될 수는 없다.

개발자들이 객체의 새로운 복제물을 생성하기 위해 요청할때, PHP 5 는 __clone() 메소드가 정의 되었는지 아닌지의 여부를 체크할 것이다. 만약 정의되지 않았다면 모든 객체의 프로퍼티를 복제할 기본적인 __clone() 을 호출할 것이다. __clone() 메소드가 정의되었다면 생성된 객체 안에 필요한 프로퍼티를 정할 의무가 있을 것이다. 편의를 위해 엔진은 소스객체로부터 모든 프로퍼티를 임포팅하는 함수를 공급해서 그것들이 소스 오브젝트의 값에 의한 복제물 과 함께 시작할 수 있도록 할 것이고 변경할 필요가 있는 프로퍼티를 단지 오버라이드 할 것이다.


Example B-11. Objects cloning

<?php
class MyCloneable
{
   static
$id = 0
;

   function
MyCloneable
() {
      
$this->id = self::$id
++;
   }

   function
__clone
() {
      
$this->address = "New York"
;
      
$this->id = self::$id
++;
   }
}

$obj = new MyCloneable
();

$obj->name = "Hello"
;
$obj->address = "Tel-Aviv"
;

print
$obj->id . "\n"
;

$obj_cloned = clone $obj
;

print
$obj_cloned->id . "\n"
;
print
$obj_cloned->name . "\n"
;
print
$obj_cloned->address . "\n"
;
?>
 

PHP 5 는 개발자로 하여름 클래스를 위해 생성자 메소드를 선언할 수 있게 한다. 생성자 메소드를 가진 클래스들은 새롭게 생성된 객체에서 이 메소드를 초기화 하는데 적당하게 호출해서 객체가 사용되기 전에 필요로 하지 않게 할 것이다.

PHP 4 에서 생성자 메소드는 클래스 자신의 이름과 같은 이름을 가진 클래스 메소드였다. 파생된 클래스로부터 부모 생성자를 호출하는 것이 매우 일반적일 때, PHP 4는 거대한 클래스 계층 주변으로 클래스를 옮기는 성가신 부분을 만들어내는 방법을 택해 작업했다. 만약 클래스가 다른 부모클래스 아래로 귀속하기 위해 옮겨졌을 때, 부모클래스 생성자의 잘 바뀌는 이름과 부모클래스 생성자를 호출하는 파생된 클래스의 코드는 수정될 것이다.

PHP 5 는 __construct()라는 이름으로 불리우는 생성자 메소드를 선언하는 표준방법을 도입하였다. 


Example B-12. using new unified constructors

<?php
class BaseClass
{
   function
__construct
() {
       print
"In BaseClass constructor\n"
;
   }
}

class
SubClass extends BaseClass
{
   function
__construct
() {
      
parent::__construct
();
       print
"In SubClass constructor\n"
;
   }
}

$obj = new BaseClass
();
$obj = new SubClass
();
?>

이전 버전과의 호환성을 위해 만약 PHP 5 가 주어진 클래스를 위한 __construct() 함수를 찾지 못한다면 클래스의 이름으로 이루어진 이전 방식의 생성자 함수를 찾을 것이다. 효과적으로 이것은 클래스가 __construct() 라는 이름을 가진 메소드를 가진 경우 이것이 다른 의미론을 위해 쓰일것이라는 의미를 가지고 있는데 호환성 문제를 가진 경우에 한해서만 해당한다.

Destructors

객체를 위해 파괴자를 정의하는 능력을 소유하는 것은 매우 유용할 수 있다. 파괴자는 디버깅을 위해, 데이터베이스의 연결을 끊을 때,기타 다른 여러가지 일을 마무리할 때 로그 메세지를 남길 수 있다. PHP 4에선느 객체 파괴자를 위한 기술이 존재하지 않았지만, PHP가 셧다운을 요청하는 도중에 실행될 등록함수를 위해 이미 지원했다. 

PHP 5 는 자바와 같은 다른 객체지향언어에서와 유사한 개념을 가진 파괴자를 도입하였다. : 객체의 파괴자를 파괴한 객체가 최종적으로 참조되었을때,  어떤 파라미터 값도 받지 않는 __destruct() 라고 이름 붙여진 클래스 메소드는 메모리에서 객체가 해제되기 전에 호출된다.

Example B-13. Destructor

<?php
class MyDestructableClass
{
   function
__construct
() {
       print
"In constructor\n"
;
      
$this->name = "MyDestructableClass"
;
   }

   function
__destruct
() {
       print
"Destroying " . $this->name . "\n"
;
   }
}

$obj = new MyDestructableClass
();
?>

생성자와 같이 부모클래스의 파괴자는 엔진에 의해 명시적으로 호출되지는 않을 것이다. 부모클래스의 파괴자를 실행하기 위해 파생된 클래스에서는 명확하게 파괴자 본문에 parent::__destruct() 를 적어 호출하여야 한다.

Constants

PHP 5 는 완전한 클래스 상수를 도입하였다:

Example B-14. Class constant example

<?php
class Foo
{
   const
constant = "constant"
;
}

echo
"Foo::constant = " . Foo::constant . "\n"
;
?>

과거에는 사용자정의된 클래스나 함수에 "const"를 붙이지 않고 실행했을 것이다.


Exceptions

PHP 4 는 예외사항 조정에 대한 요소가 없었다. PHP 5 에서는 다른 프로그래밍 언어와 유사한 예외모델을 도입하였다. "catch all"을 위해 지원하지만, "finally"조항을 위한 것이 아님을 주의하여라.

Exception 은 catch 블록에서 다시 제시될 수 있다. 또한 다양한 catch 블록에서 소유하고 있는것도 가능하다. 이러한 경우에서 잡힌 exception 은 꼭대기부터 바닥까지의 각각의 catch 블록의 클래스타입과 비교되고, 'instanceof'를 지닌 첫 블록의 매치는 실행될 것이다. catch 블록이 끝날때 실행사항은 마지막 catch 블록까지 지속된다. 만약 어떤 catch 블록도 'instanceof' 매치를 지니고 있지 않은경우, 그 다음 try/catch block이 다음 try/catch 블록이 존재하지 않고 사용가능하지 않을때까지 검색될 것이다. 이러한 경우 exception 은 exception 절을 발견하지 못하고 프로그램은 예외사항을 보여주면서 중단한다.


Example B-15. Exception creation example

<?php
try
{
  
throw new Exception('Hello'
);
}
catch (Exception $exception
) {
   echo
$exception
;
}
?>

과거에는 사용자정의된 클래스나 함수에 "catch","throw" 또는 "try"를 붙이지 않고 실행했을 것이다.

Dereferencing objects returned from functions

PHP 4 에서는 함수에 의해 반환되는 객체들의 값을 부분참조하기란 불가능했고, 더 이상의 메소드를 만드는 것은 이러한 객체를 호출하였다. PHP 5에서는 다음과 같은 것들이 가능하다 :


Example B-16. Dereferencing example

<?php
class Circle
{
   function
draw
() {
       print
"Circle\n"
;
   }
}
    
class
Square
{
   function
draw
() {
       print
"Square\n"
;
   }
}

function
ShapeFactoryMethod($shape
) {
   switch (
$shape
) {
       case
"Circle"
:
           return new
Circle
();
       case
"Square"
:
           return new
Square
();
   }
}

ShapeFactoryMethod("Circle")->draw
();
ShapeFactoryMethod("Square")->draw
();
?>

Static member variables initialization

정적 클래스의 정적 멤버 변수가 이제 초기화될 수 있다.


Example B-17. Static variable initialization example

<?php
class foo
{
   static
$my_static = 5
;
  
public $my_prop = 'bla'
;
}

print
foo::$my_static
;
$obj = new foo
;
print
$obj->my_prop
;
?>
 

PHP 5 는 메소드를 정적으로 선언하기 위해 'static' 키워드를 도입하였다. 그래서 객체의 외부 전후에서 호출할 수 있다.


Example B-18. Static Methods example

<?php
class Foo
{
  
public static function aStaticMethod
() {
      
// ...
  
}
}

Foo::aStaticMethod
();
?>

가상변수 $this 는 static으로 선언된 메소드 안에서는 사용할 수 없다.


instanceof

PHP 5 는 객체가 클래스의 인스턴스건 아니건간에 그것을 조사하고 클래스를 확장하고 인터페이스조건을 제시하게 하기 위한 instanceof  키워드를 도입하였다.


Example B-19. instanceof example

<?php
class baseClass
{ }

$a = new baseClass
;

if (
$a instanceof baseClass
) {
   echo
"Hello World"
;
}
?>
 

Static은 개발자로 하여금 참조의 방식으로 변수의 값을 상수로 전달하도록 하는 컴파일 도중에 다루어진다. 이러한 변화는 또한 그들의 성능을 엄청나게 향상시켰지만 상수로의 우회적 참조가 더이상의 일을 할 수 없음을 의미한다.


Parameters passed by reference

참조에 의해 함수로 전달된 파라미터값은 아마 이제부터 기본값을 가질 수 있을 것이다.


Example B-20.

<?php
function my_function(&$var = null
) {
   if (
$var === null
) {
       die(
"$var needs to have a value"
);
   }
}
?>
 

__autoload() 요격실행 함수는 선언되지 않은 클래스가 명시화되었을 때, 자동적으로 호출될 것이다. 해당 클래스의 이름은 __autoload() 요격실행 함수로 인자처럼 전달될 것이다.


Example B-21. __autoload() example

<?php
function __autoload($className
) {
   include_once
$className . ".php"
;
}

$object = new ClassName
;
?>
 

메소트 호출과 프로퍼티 접근은 __call(), __get() 그리고 __set() 메소드에 의해 오버로드 될 수 있다.


Example B-22. __get() and __set()

<?php
class Setter
{
  
public $n
;
  
public $x = array("a" => 1, "b" => 2, "c" => 3
);

   function
__get($nm
) {
       print
"Getting [$nm]\n"
;

       if (isset(
$this->x[$nm
])) {
          
$r = $this->x[$nm
];
           print
"Returning: $r\n"
;
           return
$r
;
       } else {
           print
"Nothing!\n"
;
       }
   }

   function
__set($nm, $val
) {
       print
"Setting [$nm] to $val\n"
;

       if (isset(
$this->x[$nm
])) {
          
$this->x[$nm] = $val
;
           print
"OK!\n"
;
       } else {
           print
"Not OK!\n"
;
       }
   }
}


$foo = new Setter
();
$foo->n = 1
;
$foo->a = 100
;
$foo->a
++;
$foo->z
++;
var_dump($foo
);
?>

Example B-23. __get() example

<?php
class Caller
{
  
private $x = array(1, 2, 3
);

   function
__call($m, $a
) {
       print
"Method $m called:\n"
;
      
var_dump($a
);
       return
$this->x
;
   }
}

$foo = new Caller
();
$a = $foo->test(1, "2", 3.4, true
);
var_dump($a
);
?>
 

객체는 아마 foreach와 같은 방식을 사용하였을때의 오버로딩하는 방법으로 반복될 수 있을 것이다. 기본적인 행동은 모든 프로퍼티를 반복한다.


Example B-24. Object iteration example

<?php
class Foo
{
  
public $x = 1
;
  
public $y = 2
;
}

$obj = new Foo
;

foreach (
$obj as $prp_name => $prop_value
) {
  
// using the property
}
?>

인스턴스의 각각의 클래스는 Traversable이라는 빈 인터페이스를 실행할 foreach로 반복될 수 있다. 따가서 적합하게 실행되는 몇몇 객체들은 foreach와 합께 사용될 수 있다.

IteratorAggregate 와 Iterator 인터페이스는 PHP 코드에서 반복사용되는 방법을 상술할 수 있도록 한다. 그것들에 있어 첫번째는 Iterator 인터페이스를 이행하거나 반복가능한 내부 클래스에서 명시회되는 배열이나 객체를 반드시 리턴해야 하는 getIterator() 라는 메소드를 포함한다.


Example B-25. Iterator creation example

<?php
class ObjectIterator implements Iterator
{

  
private $obj
;
  
private $num
;

   function
__construct($obj
) {
      
$this->obj = $obj
;
   }
   function
rewind
() {
      
$this->num = 0
;
   }
   function
valid
() {
       return
$this->num < $this->obj->max
;
   }
   function
key
() {
       return
$this->num
;
   }
   function
current
() {
       switch(
$this->num
) {
           case
0: return "1st"
;
           case
1: return "2nd"
;
           case
2: return "3rd"
;
           default: return
$this->num."th"
;
       }
   }
   function
next
() {
      
$this->num
++;
   }
}

class
Object implements IteratorAggregate
{

  
public $max = 3
;

   function
getIterator
() {
       return new
ObjectIterator($this
);
   }
}

$obj = new Object
;

// this foreach ...
foreach($obj as $key => $val
) {
   echo
"$key = $val\n"
;
}

// matches the following 7 lines with the for directive.
$it = $obj->getIterator
();
for(
$it->rewind(); $it->valid(); $it->next
()) {
  
$key = $it->current
();
      
$val = $it->key
();
         echo
"$key = $val\n"
;
}
unset(
$it
);
?>
 

새로운 __METHOD__ 가상 상수는 현재 클래스와 메소드 내부에서 메소드가 사용될 때의 메소드를 보여주고, 클래스 밖에서 사용될때의 함수를 보여준다.


Example B-26. __METHOD__ use example

<?php
class Foo
{
   function
show
() {
       echo
__METHOD__
;
   }
}

class
Bar extends <