피카사 웹 앨범으로 PHP 응용 프로그램 개발하기

아범 사이트에는 정말 배울게 많은것 같다

http://www.ibm.com/developerworks/kr/library/x-picasalbum/ 




피카사 웹 앨범 데이터 API 이해하기

PHP 코드로 돌입하기 전에 먼저 피카사 웹 앨범 데이터 API를 이해하고 넘어가자. 여느 REST 기반 서비스와 마찬가지로, 가장 먼저 특정 URL로 HTTP 요청을 보낸다. 이 HTTP 요청은 입력 매개변수를 한 개 이상 포함하며, 서버는 요청 결과를 Atom 피드나 RSS 피드로 반환한다. 두 피드 모두 XML을 인식하는 클라이언트라면 문제 없이 구문 분석이 가능하다.

전형적인 피카사 피드는 많은 정보를 포함한다. 예를 들어, 웹 브라우저에 주소란에 http://picasaweb.google.com/data/feed/api/user/userid?kind=photo을 입력해 본다. 여기서 userid는 자신의 구글 계정 사용자 이름으로 대체한다. 사용자가 이미 피카사 웹 앨범에 앨범을 만들고 사진을 올렸다면 Listing 1과 비슷한 결과를 얻는다.

피드를 간략히 훑으면서 기본 형식에 익숙해지자.

  • 피카사 웹 앨범 데이터 API는 REST 요청에 피드로 응답한다. 피드 종류는 앨범 피드, 사진 피드, 사용자 피드, 사용자 연락처 피드 등으로 다양하다. 그래서 대다수 XML 응답은 <feed> 엘리먼트가 루트 엘리먼트다. <feed> 엘리먼트는 <link> 엘리먼트와 <openSearch:> 엘리먼트를 포함하는데, <link> 엘리먼트는 결과 집합의 현재 페이지 URL, 다음 페이지 URL, 이전 페이지 URL을 포함한다. <openSearch:> 엘리먼트는 검색을 수행한 통계 수치를 포함한다.
  • 가장 바깥에 있는 <feed> 엘리먼트는 <entry> 엘리먼트를 하나 이상 포함하는데, 각 <entry> 엘리먼트는 질의에 일치하는 사진 관련 정보를 포함한다. 여기에는 사진 제목, 파일 이름, 게시 날짜, 작성자 등이 들어간다. 각 <entry> 엘리먼트는 <link> 엘리먼트도 포함하는데, 여기서 <link> 엘리먼트는 사진을 보고 편집할 URL을 포함한다.
  • <entry> 엘리먼트 내 <gphoto:> 엘리먼트는 사진 크기, 치수, 앨범, 주석 수 등 사진 정보를 상세히 포함한다.
  • <entry> 엘리먼트 내 <media:group> 엘리먼트는 사진 키워드와 미리보기 이미지 링크를 포함한다.

SimpleXML로 사진 가져오기

이제 PHP와 SimpleXML을 사용하여 피카사 웹 앨범 피드를 분석하겠다. Listing 2는 Listing 1에서 소개한 피드 예제를 받는다. 그런 다음, SimpleXML을 사용하여 관련 정보를 추출한 후 형식에 맞춰 웹 페이지에 뿌린다.


Listing 2: SimpleXML로 사진 목록 가져오기
            
<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Listing album contents</title>
    <style>
    body {
      font-family: Verdana;      
    }
    h2 {
      color: red; 
      text-decoration: none;  
    }
    span.attr {
      font-weight: bolder;  
    }
    img {
      float: left;  
    }
    </style>    
  </head>
  <body>
    <?php
    $userid = 'userid%40googlemail.com';

    // 피드 URL을 생성한다.
    $feedURL = "http://picasaweb.google.com/data/feed/api/user/$userid?kind=photo";
    
    // SimpleXML 객체로 피드를 읽는다.
    $sxml = simplexml_load_file($feedURL);
    
    // 앨범 이름과 사진 개수를 얻는다.
    $counts = $sxml->children('http://a9.com/-/spec/opensearchrss/1.0/');
    $total = $counts->totalResults; 
    ?>
    <h1><?php echo $sxml->title; ?></h1>
    <?php echo $total; ?> photo(s) found.
    <p/>

    <?php
    // 앨범에 들어있는 항목을 순회한다.
    // 항목별로 제목, 크기, 치수, 태그, 미리 보기 이미지를 출력한다.
    foreach ($sxml->entry as $entry) {
      $title = $entry->title;
      $summary = $entry->summary;
      
      $gphoto = $entry->children('http://schemas.google.com/photos/2007');
      $size = $gphoto->size;
      $height = $gphoto->height;
      $width = $gphoto->width;
      
      $media = $entry->children('http://search.yahoo.com/mrss/');
      $thumbnail = $media->group->thumbnail[1];
      $tags = $media->group->keywords;
      
      echo "<h2>$summary</h2>\n";
      echo "<table><tr><td><img src=\"" . 
      $thumbnail->attributes()->{'url'} . "\"/></td>\n";
      echo "<td><span class=\"attr\">File</span>: $title 
      <br />\n";
      echo "<span class=\"attr\">Size</span>: $size bytes 
      ($height x $width) <br />\n";
      echo "<span class=\"attr\">Tags</span>: $tags 
      </td></tr></table>\n";
    }
    ?>
    
  </body>
</html>
        

그림 1은 Listing 2가 출력하는 결과다.


그림 1. 사진을 열거하는 웹 페이지
사진을 열거하는 웹 페이지 

Listing 2를 구체적으로 살펴보면, 가장 먼저 simplexml_load_file() 객체를 사용하여 피드 URL로 요청을 보낸 후 응답을 SimpleXML 객체로 변환한다. 그런 다음, foreach() 루프를 사용하여 <entry> 엘리먼트를 순회하면서 그림 1에 출력한 정보를 하나씩 추출한다. <entry> 아래 있는 자식 노드는 SimpleXML 객체 속성으로 참조한다. 예를 들어, <title> 노드는 $entry->title, <summary> 노드는 $entry->summary 등으로 표현한다. 키워드와 미리 보기 이미지는 각 <entry> 아래에 <media:group>에서 얻는다.

사용자 피드와 앨범 피드에서 정보 가져오기

이런 방법을 사용하면 특정 사용자가 생성한 앨범 목록을 가져오기도 아주 쉽다. Listing 2에서 보여준 피드 URL을 그대로 사용하되 매개변수 몇 개만 바꾸면 된다. Listing 3은 피드를 가져와 분석하는 방법을 보여준다.


Listing 3: SimpleXML로 앨범 목록 가져오기
            
<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Listing albums</title>
    <style>
    body {
      font-family: Verdana;
    }
    </style>
  </head>
  <body>
    <h1>Album Listing</h2>
    <?php
    $userid = 'userid%40googlemail.com';
    
    // 피드 URL을 생성한다.
    $feedURL = "http://picasaweb.google.com/data/feed/api/user/$userid?kind=album";
    
    // SimpleXML 객체로 피드를 읽는다.
    $sxml = simplexml_load_file($feedURL);
    
    // 앨범 이름과 사진 개수를 얻는다.
    echo "<ul>";
    foreach ($sxml->entry as $entry) {
      $title = $entry->title;
      $gphoto = $entry->children('http://schemas.google.com/photos/2007');
      $numphotos = $gphoto->numphotos;      
      echo "<li>$title - $numphotos photo(s)</li>\n";
    }
    echo "</ul>";
    ?>
    
  </body>
</html> 
        

그림 2는 Listing 3이 출력하는 결과다.


그림 2. 앨범 목록을 열거하는 웹 페이지
앨범 목록을 열거하는 웹 페이지 

특정 앨범에만 포함된 사진 목록을 가져오려면 피드 URL에 앨범 이름을 지정한다. Listing 4는 피드를 가져와 분석하는 방법을 보여준다.


Listing 4: SimpleXML로 앨범에 든 사진 목록 가져오기
            
<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Listing album contents</title>
    <style>
    body {
      font-family: Verdana;
    }
    h2 {
      color: red;
      text-decoration: none;
    }
    span.attr {
      font-weight: bolder;
    }
    img {
      float: left;
    }
    </style>
  </head>
  <body>
    <?php
    $userid = 'userid%40googlemail.com';
    $album = 'France2008';
    
    // 피드 URL을 생성한다.
    $feedURL = "http://picasaweb.google.com/data/feed/api/user/$userid/album/$album";
    
    // SimpleXML 객체로 피드를 읽는다.
    $sxml = simplexml_load_file($feedURL);
    
    // 앨범 이름과 사진 개수를 얻는다.
    $counts = $sxml->children('http://a9.com/-/spec/opensearchrss/1.0/');
    $total = $counts->totalResults; 
    ?>
    <h1><?php echo $sxml->title; ?></h1>
    <?php echo $total; ?> photo(s) found.
    <p/>

    <?php
    // 앨범에 들어있는 항목을 순회한다.
    // 항목별로 제목, 크기, 치수, 태그, 미리 보기 이미지를 출력한다.
    foreach ($sxml->entry as $entry) {
      $title = $entry->title;
      $summary = $entry->summary;
      
      $gphoto = $entry->children('http://schemas.google.com/photos/2007');
      $size = $gphoto->size;
      $height = $gphoto->height;
      $width = $gphoto->width;
      
      $media = $entry->children('http://search.yahoo.com/mrss/');
      $thumbnail = $media->group->thumbnail[1];
      $tags = $media->group->keywords;
      
      echo "<h2>$summary</h2>\n";
      echo "<table><tr><td><img src=\"" . 
      $thumbnail->attributes()->{'url'} . "\"/></td>\n";
      echo "<td><span class=\"attr\">File</span>: $title 
      <br />\n";
      echo "<span class=\"attr\">Size</span>: $size bytes 
      ($height x $width) <br />\n";
      echo "<span class=\"attr\">Tags</span>: $tags 
      </td></tr></table>\n";
    }
    ?>
    
  </body>
</html>   
        

그림 3은 Listing 4가 출력하는 결과다.


그림 3. 앨범에 든 사진을 열거하는 웹 페이지
앨범에 든 사진을 열거하는 웹 페이지 

젠드 GData 클라이언트 라이브러리로 사진 가져오기

지금까지 PHP를 사용하여 피카사 웹 앨범에서 앨범과 사진 정보를 가져오는 방법을 소개했다. 코드를 보면 알겠지만 아주 간단하다. 하지만 앞서 소개한 방법은 읽기만 가능하다는 단점이 있다. 새 사진이나 앨범을 추가하는 등 쓰기 접근이 필요한 복잡한 작업을 수행하려면 PHP 응용 프로그램에 사용자 인증 단계를 추가해야 한다. 구글이 인정하는 사용자 인증 방법은 AuthSub과 ClientLogin 두 가지다.

PHP 코드에서 인증 단계를 직접 구현하려면 여러 가지로 번거롭다. 인증 과정에서 돌발적으로 발생하는 상황까지 모두 고려하려면 상당한 설계와 코드가 필요하다. 다행스럽게도 젠드 GData 클라이언트 라이브러리를 사용하면 골치를 앓을 필요가 없다. 젠드 GData 클라이언트 라이브러리는 PHP 프로그램과 구글 데이터 API를 통합하려는 개발자를 위해 특별히 설계된 라이브러리로, 인증 과정에서 벌어지는 갖가지 시나리오를 모두 알아서 처리한다. 이 라이브러리는 구글 데이터 API에 편리한 객체 지향 인터페이스를 제공하며 (인증을 포함하여) 일반적인 작업 대다수를 캡슐화하여 제공한다. 그러므로 개발자는 응용 프로그램이 수행하는 핵심 기능에만 집중하면 된다. 라이브러리를 내려받는 링크는 참고자료에서 제공한다.

Listing 5는 젠드 GData 클라이언트 라이브러리를 사용하여 Listing 4와 같은 기능을 구현하는 코드다.


Listing 5: 젠드 GData 클라이언트 라이브러리로 앨범에 든 사진 목록 가져오기
            
<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Listing album contents</title>
    <style>
    body {
      font-family: Verdana;
    }
    h2 {
      color: red;
      text-decoration: none;
    }
    span.attr {
      font-weight: bolder;
    }
    img {
      float: left;
    }
    </style>
  </head>
  <body>
    <?php
    // 라이브러리를 올린다.
    require_once 'Zend/Loader.php';
    Zend_Loader::loadClass('Zend_Gdata');
    Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
    Zend_Loader::loadClass('Zend_Gdata_Photos');
    Zend_Loader::loadClass('Zend_Http_Client');
    
    // 피카사 서비스를 위한 인증된 HTTP 클라이언트를 생성한다.
    $svc = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
    $user = "userid@gmail.com";
    $pass = "secret";
    $client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $svc);
    $gphoto = new Zend_Gdata_Photos($client);
    
    // 앨범 피드를 얻기 위해 질의를 생성한다.
    $query = $gphoto->newAlbumQuery();
    $query->setUser("default");
    $query->setAlbumName("France2008");
    
    // 앨범 피드를 얻어 해석한다.
    // 앨범 이름과 사진 개수를 얻는다.
    try {
      $feed = $gphoto->getAlbumFeed($query);
    } catch (Zend_Gdata_App_Exception $e) {
      echo "Error: " . $e->getResponse();
    }
    ?>
    <h1><?php echo $feed->getTitle(); ?></h1>
    <?php echo $feed->getTotalResults(); ?> photo(s) found.
    <p/>

    <?php
    // 각 사진 항목을 처리한다.
    // 항목별로 제목, 크기, 치수, 태그, 미리 보기 이미지를 출력한다.
    foreach ($feed as $entry) {
      $title = $entry->getTitle();
      $summary = $entry->getSummary();
      $thumbnail = $entry->getMediaGroup()->getThumbnail();
      $tags = $entry->getMediaGroup()->getKeywords();
      $size = $entry->getGphotoSize();
      $height = $entry->getGphotoHeight();
      $width = $entry->getGphotoWidth();
      
      echo "<h2>$summary</h2>\n";
      echo "<table><tr><td><img src=\"" . 
      $thumbnail[1]->url . "\"/></td>\n";
      echo "<td><span class=\"attr\">File</span>: $title 
      <br />\n";
      echo "<span class=\"attr\">Size</span>: $size bytes 
      ($height x $width) <br />\n";
      echo "<span class=\"attr\">Tags</span>: $tags 
      </td></tr></table>\n";
    }
    ?>

  </body>
</html>
        

Listing 5를 구체적으로 살펴보면, 가장 먼저 젠드 클래스 라이브러리를 올린 후 Zend_Http_Client 클래스 인스턴스를 초기화한다. 이 클라이언트에 사용자 인증 정보를 제공한 후 피카사 서비스와 인증된 연결을 맺는다. 일단 인증된 연결을 맺은 다음에는getAlbumFeed() 메서드로 앨범 피드를 가져온다. 이 메서드는 AlbumQuery 객체를 받는데, AlbumQuery 객체는 두 매개변수로 구성된다.

  • 앨범 소유자의 피카사 사용자 이름
  • 앨범 이름

getAlbumFeed() API가 반환하는 결과는 Listing 1에서 보았던 XML 피드와 비슷하다. getAlubmFeed() 메서드는 결과를 분석하여 PHP 객체로 변환한다. 이 객체는 get 메서드와 set 메서드가 있어서, XML 피드에서 객체/속성 방식으로 구체적인 노드 정보를 추출하기가 수월하다. 예를 들어, getSummary() 메서드는 사진 요약 정보를 반환하며, getGphotoSize() 메서드는 사진 크기를 바이트 단위로 반환한다.

그림 4는 Listing 5가 출력하는 결과다.


그림 4. 앨범에 든 사진을 열거하는 웹 페이지
앨범에 든 사진을 열거하는 웹 페이지 

새 사진 추가하기

지금까지 앨범과 사진을 열거하는 방법을 살펴보았다. 그렇다면 새로운 사진을 추가하는 방법은 무엇일까? 생각보다 복잡하지 않다.

새 사진을 추가하려면 POST 방식으로 이미지 파일과 관련 메타 정보를 앨범 피드 URL로 전송하면 된다. 이 때 정보 블록은 MIME으로 인코딩한다. 즉, 정보 블록에서 일부는 <entry> XML 정보이고 일부는 이진 자료라는 뜻이다. Listing 6은 이런 정보 블록을 보여준다.


Listing 6: 새 사진과 메타 정보를 추가하는 POST 패킷 예제
            
--=_00fb9c5957c74e05312cbc2f9d1d09b8
Content-Type: application/atom+xml
<atom:entry xmlns:atom="http://www.w3.org/2005/Atom">
  <atom:category term="http://schemas.google.com/photos/2007#photo" 
  scheme="http://schemas.google.com/g/2005#kind"/>
  <atom:summary type="text">Notre Dame, Paris</atom:summary>
  <media:group xmlns:media="http://search.yahoo.com/mrss/">
    <media:keywords>church, paris</media:keywords>
  </media:group>
</atom:entry>

--=_00fb9c5957c74e05312cbc2f9d1d09b8
Content-Type: image/jpeg

[binary data] 
        

젠드 라이브러리를 사용하면 사진을 추가하기가 더욱 쉬워진다. 단순히 insertPhotoEntry() 메서드를 호출하면 된다. 그러면 메서드가 알아서 Listing 6과 같은 POST 패킷을 생성한 후 앨범 피드로 전송한다. Listing 7은 사용자로부터 사진 파일, 제목, 태그를 받은 후 젠드 라이브러리로 POST 패킷을 생성하여 앨범에 저장하는 코드다.


Listing 7: 새 사진 추가
            
<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Adding photos to an album</title>
    <style>
    body {
      font-family: Verdana;
    }
    li {
      border-bottom: solid black 1px;
      margin: 10px; 
      padding: 2px; 
      width: auto;
      padding-bottom: 20px;
    }
    h2 {
      color: red; 
      text-decoration: none;  
    }
    span.attr {
      font-weight: bolder;  
    }
    </style>
  </head>
  <body>
    <h1>Add Photo</h1>
    <?php if (!isset($_POST['submit'])) { ?>
    <form method="post" action="<?php 
     echo htmlentities($_SERVER['PHP_SELF']); ?>" enctype="multipart/form-data">
      Title: <br/>
      <input name="title" type="text" size="25" /><p/>
      File to upload: <br/>
      <input name="photofile" type="file" /><p/>      
      Tags: <br/>
      <input name="tags" type="text" size="25" /><p/>
      <input name="submit" type="submit" value="Save" />
    </form>
    <?php
    } else {
      // 클래스를 올린다.
      require_once 'Zend/Loader.php';
      Zend_Loader::loadClass('Zend_Gdata');
      Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
      Zend_Loader::loadClass('Zend_Gdata_Photos');
      Zend_Loader::loadClass('Zend_Http_Client');
      
      // 서비스에 접속한다.
      $svc = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
      $user = "userid@gmail.com";
      $pass = "secret";
      $client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $svc);
      $gphoto = new Zend_Gdata_Photos($client);
      
      // 입력을 검사한다.
      if (empty($_POST['title'])) {
        die('ERROR: Missing title');
      } 
      
      // 입력을 검사한다.
      $title = htmlentities($_POST['title']);
      $tags = htmlentities($_POST['tags']);

      // 앨범 이름을 설정한다.
      $albumName = "France2008";

      // 사진 객체를 만든다.
      // 서버에 저장한다.
      try {
        $photo = $gphoto->newPhotoEntry();
        
        // 파일을 설정한다.
        $file = $gphoto->newMediaFileSource($_FILES['photofile']['tmp_name']);
        $file->setContentType("image/jpeg");
        $photo->setMediaSource($file);
        
        // 제목을 설정한다.
        $photo->setSummary($gphoto->newSummary($title));
        
        // 태그를 설정한다.
        $photo->mediaGroup = new Zend_Gdata_Media_Extension_MediaGroup();
        $keywords = new Zend_Gdata_Media_Extension_MediaKeywords();
        $keywords->setText($tags);
        $photo->mediaGroup->keywords = $keywords;
        
        // 앨범에 링크를 건다.
        $album = $gphoto->newAlbumQuery();
        $album->setUser($user);
        $album->setAlbumName($albumName);
        
        // 사진을 저장한다.
        $gphoto->insertPhotoEntry($photo, $album->getQueryUrl()); 
      } catch (Zend_Gdata_App_Exception $e) {
        echo "Error: " . $e->getResponse();
      }
      echo 'Photo successfully added!';
    }
    ?>
  </body>
</html>    
        

Listing 7은 실제로 두 부분으로 나뉜다.

  • 웹 폼
  • 폼으로 제출된 정보를 처리하는 PHP 코드

그림 5는 폼 모습이다.


그림 5. 새 사진을 추가하는 웹 폼
새 사진을 추가하는 웹 폼 

사용자가 업로드할 이미지를 선택하고 제목과 태그를 입력한 후 폼을 제출하면 나머지 절반을 차지하는 PHP 코드가 실행된다. 먼저, HTTP 클라이언트가 초기화되고 피카사 웹 앨범 데이터 API와 인증된 연결을 맺는다. 다음으로, 사용자가 입력한 정보를 검증한 후PhotoEntry() 객체를 생성하고 초기화한다. 사용자가 입력한 새 정보는 이 객체에 저장된다.

다음으로, 사용자가 폼에 입력한 키워드와 제목을 각각 mediaGroup 속성과 setSummary() 메서드로 만들어진 객체에 첨부한다. PHP는 특수한 전역 변수인 $_FILES에 업로드한 파일 이름을 저장하므로, 여기서 파일 이름을 추출하여 setMediaSource() 메서드로 만들어진 객체에 파일을 첨부한다. 마지막으로, setAlbumName() 메서드로 사진을 추가할 앨범을 저장한다(기본 앨범이나 drop box에 사진을 추가하려면 default로 설정한다).

다양한 객체 매개변수를 모두 설정한 후에는 insertPhotoEntry() 메서드를 호출하여 사진과 메타 정보를 구글 서버에 실제로 저장한다. 사진을 추가한 후에는 해당 앨범에서 결과를 바로 확인할 수 있다.

그림 6은 새 사진을 성공적으로 추가한 후 앨범을 살펴본 모습이다.


그림 6. 새 사진을 추가한 결과
새 사진을 추가한 결과 

사진 삭제하고 수정하기

사진을 삭제하려면 사진 URL에 DELETE 요청을 보낸다. 젠드 라이브러리를 사용한다면 사진 ID와 앨범 ID로 사진 URL을 구성한 후getPhotoEntry() 메서드로 사진 객체를 얻는다. 그런 다음, 사진 객체에 delete() 메서드를 호출한다. 자세한 과정은 Listing 8을 참조한다.


Listing 8: 사진 지우기
            
<?php
// 클래스를 올린다.
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Gdata_Photos');
Zend_Loader::loadClass('Zend_Http_Client');

// 서비스에 연결한다.
$svc = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$user = "userid@gmail.com";
$pass = "secret";
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $svc);
$gphoto = new Zend_Gdata_Photos($client);

// 사진 항목을 얻는다.
// 항목을 지운다.
try {
  $photo = $gphoto->getPhotoEntry( 'http://picasaweb.google.com/data/entry/api/
  user/xxxxx/albumid/yyyyy/photoid/zzzzz');
  $photo->delete();
} catch (Zend_Gdata_App_Exception $e) {
  echo "Error: " . $e->getResponse();
}        
echo 'Photo successfully deleted!';  
?>
        

사진을 편집할 때도 getPhotoEntry() 메서드를 사용한다. 이번에는 객체 속성에 새 값을 설정한 후 save() 메서드를 호출하여 객체를 서버로 다시 저장한다. 자세한 과정은 Listing 9를 참조한다.


Listing 9: 사진 수정하기
            
<?php
// 클래스를 올린다.
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Gdata_Photos');
Zend_Loader::loadClass('Zend_Http_Client');

// 서비스에 연결한다.
$svc = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$user = "userid@gmail.com";
$pass = "secret";
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $svc);
$gphoto = new Zend_Gdata_Photos($client);

// 사진 항목을 얻는다.
// 항목을 변경한다.
try {
  $photo = $gphoto->getPhotoEntry('http://picasaweb.google.com/
  data/entry/api/user/xxxxx/albumid/yyyyy/photoid/zzzzz');

  // 새로운 제목을 설정한다.
  $photo->setSummary($gphoto->newSummary('New title'));
  
  // 새로운 태그를 설정한다.
  $photo->mediaGroup = new Zend_Gdata_Media_Extension_MediaGroup();
  $keywords = new Zend_Gdata_Media_Extension_MediaKeywords();
  $keywords->setText('new,tags');
  $photo->mediaGroup->keywords = $keywords;
  
  $photo->save();
} catch (Zend_Gdata_App_Exception $e) {
  echo "Error: " . $e->getResponse();
}        
echo 'Photo successfully modified!';  
?>
        

피드 결과 걸러내기

피카사 웹 앨범 데이터 API를 사용하면 사용자가 임의로 피드를 제어할 수 있다. 피드로 가져올 결과 수를 제한하거나, 지정한 검색 조건에 만족하는 피드만 가져올 수 있다는 뜻이다. 예를 들어, Listing 10은 피드 URL에 'max-results'라는 매개변수를 추가하여 피드가 반환하는 결과 수를 제한한다.


Listing 10: 피드 결과 제한하기
            
<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Restricting feed results</title>
    <style>
    body {
      font-family: Verdana;
    }
    h2 {
      color: red; 
      text-decoration: none;
    }
    span.attr {
      font-weight: bolder;
    }
    img {
      float: left;
    }
    </style>
  </head>
  <body>
    <?php
    $userid = 'userid%40googlemail.com';
    $album = 'France2008';
    
    // 피드 URL을 만든다.
    $feedURL = "http://picasaweb.google.com/data/feed/api/
    user/$userid/album/$album?max-results=3";
    
    // SimpleXML 객체로 피드를 읽는다.
    $sxml = simplexml_load_file($feedURL);
    
    // 앨범 이름과 사진 개수를 얻는다.
    $counts = $sxml->children('http://a9.com/-/spec/opensearchrss/1.0/');
    $total = $counts->totalResults; 
    ?>
    <h1><?php echo $sxml->title; ?></h1>
    <?php echo $total; ?> photo(s) found.
    <p/>

    <?php
    // 앨범에 들어있는 항목을 순회한다.
    // 항목별로 제목, 크기, 치수, 태그, 미리 보기 이미지를 출력한다.
    foreach ($sxml->entry as $entry) {
      $title = $entry->title;
      $summary = $entry->summary;
      
      $gphoto = $entry->children('http://schemas.google.com/photos/2007');
      $size = $gphoto->size;
      $height = $gphoto->height;
      $width = $gphoto->width;
      
      $media = $entry->children('http://search.yahoo.com/mrss/');
      $thumbnail = $media->group->thumbnail[1];
      $tags = $media->group->keywords;
      
      echo "<h2>$summary</h2>\n";
      echo "<table><tr><td><img src=\"" . 
      $thumbnail->attributes()->{'url'} . "\"/></td>\n";
      echo "<td><span class=\"attr\">File</span>: $title 
      <br />\n";
      echo "<span class=\"attr\">Size</span>: $size 
      ($height x $width) <br />\n";
      echo "<span class=\"attr\">Tags</span>: $tags 
      </td></tr></table>\n";
    }
    ?>
    
  </body>
</html>
        

지정한 특정 검색 조건에 만족하는 항목만 가져오려면 q 매개변수를 사용한다. 그러면 피카사는 검색 문자열에 일치하는 제목, 설명, 태그를 찾는다. Listing 11은 태그가 'church'인 사진을 모두 가져온다.


Listing 11: 키워드로 사진 검색하기
            
<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Searching photos by tag</title>
    <style>
    body {
      font-family: Verdana;
    }
    h2 {
      color: red; 
      text-decoration: none;
    }
    span.attr {
      font-weight: bolder;
    }
    img {
      float: left;
    }
    </style>
  </head>
  <body>
    <?php
    $userid = 'userid%40googlemail.com';
    $album = 'France2008';
    
    // 피드 URL을 만든다.
    $feedURL = "http://picasaweb.google.com/data/feed/api/user/
    $userid/album/$album?tag=church";
    
    // SimpleXML 객체로 피드를 읽는다.
    $sxml = simplexml_load_file($feedURL);
    
    // 앨범 이름과 사진 개수를 얻는다.
    $counts = $sxml->children('http://a9.com/-/spec/opensearchrss/1.0/');
    $total = $counts->totalResults; 
    ?>
    <h1><?php echo $sxml->title; ?></h1>
    <?php echo $total; ?> photo(s) found.
    <p/>

    <?php
    // 앨범에 들어있는 항목을 순회한다.
    // 항목별로 제목, 크기, 치수, 태그, 미리 보기 이미지를 출력한다.
    foreach ($sxml->entry as $entry) {
      $title = $entry->title;
      $summary = $entry->summary;
      
      $gphoto = $entry->children('http://schemas.google.com/photos/2007');
      $size = $gphoto->size;
      $height = $gphoto->height;
      $width = $gphoto->width;
      
      $media = $entry->children('http://search.yahoo.com/mrss/');
      $thumbnail = $media->group->thumbnail[1];
      $tags = $media->group->keywords;
      
      echo "<h2>$summary</h2>\n";
      echo "<table><tr><td><img src=\"" . 
      $thumbnail->attributes()->{'url'} . "\"/></td>\n";
      echo "<td><span class=\"attr\">File</span>: $title 
      <br />\n";
      echo "<span class=\"attr\">Size</span>: $size 
      ($height x $width) <br />\n";
      echo "<span class=\"attr\">Tags</span>: $tags 
      </td></tr></table>\n";
    }
    ?>
    
  </body>
</html>     
        

그림 7은 Listing 11을 실행한 결과 예다.


그림 7. 키워드로 사진 검색하기
키워드로 사진 검색하기 

코드 통합하기

지금까지 살펴본 정보를 모두 통합하여 PHP 응용 프로그램을 작성하겠다. 우리가 작성할 응용 프로그램은 피카사 웹 앨범 데이터 API를 사용하여 앨범에서 사진을 보고, 삭제하고, 추가하고, 검색하는 프로그램이다. 이 프로토타입 프로그램은 스크립트 세 개로 이루어진다(코드는 다운로드 절에서 제공한다).

  • 'list.php': 앨범에 있는 사진을 열거한다. 사진을 검색하고 추가하고 삭제하는 링크도 제공한다.
  • 'add.php': 새 사진을 추가하는 폼을 표시하고 폼이 제출하는 정보를 처리한다.
  • 'delete.php': 지정한 사진을 삭제한다.

Listing 12에서 보듯이, 'list.php'는 Listing 4를 수정한 버전이다. 각 사진에 delete 링크를 추가했으며, 또한 페이지에 검색 폼을 추가했다.


Listing 12: 사진 열거하기
            
<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Listing album contents</title>
    <style>
    body {
      font-family: Verdana;
    }
    h2 {
      color: red; 
      text-decoration: none;
    }
    span.attr {
      font-weight: bolder;
    }
    img {
      float: left;
    }
    </style>
  </head>
  <body>
    <?php
    // 라이브러리를 올린다.
    require_once 'Zend/Loader.php';
    Zend_Loader::loadClass('Zend_Gdata');
    Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
    Zend_Loader::loadClass('Zend_Gdata_Photos');
    Zend_Loader::loadClass('Zend_Http_Client');
    
    // 피카사 서비스를 위해 인증된 HTTP 클라이언트를 생성한다.
    $svc = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
    $user = "userid@gmail.com";
    $pass = "secret";
    $client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $svc);
    $gphoto = new Zend_Gdata_Photos($client);
    
    // 앨범 피드를 얻기 위한 질의를 생성한다.
    $query = $gphoto->newAlbumQuery();
    $query->setUser("default");
    $query->setAlbumName("France2008");
    
    // 검색 용어를 필터한다.
    if(isset($_GET['q'])) {
      $query->setQuery($_GET['q']);
    }
    
    // 앨범 피드를 얻어 해석한다.
    // 앨범 이름과 사진 개수를 얻는다.
    try {
      $feed = $gphoto->getAlbumFeed($query);
    } catch (Zend_Gdata_App_Exception $e) {
      echo "Error: " . $e->getResponse();
    }
    ?>
    <h1><?php echo $feed->getTitle(); ?></h1>
    <?php echo $feed->getTotalResults(); ?> photo(s) found.
    <p/>

    <?php
    // 앨범에 들어있는 항목을 순회한다.
    // 항목별로 제목, 크기, 치수, 태그, 미리 보기 이미지를 출력한다.
    foreach ($feed as $entry) {
      $title = $entry->getTitle();
      $summary = $entry->getSummary();
      $thumbnail = $entry->getMediaGroup()->getThumbnail();
      $tags = $entry->getMediaGroup()->getKeywords();
      $size = $entry->getGphotoSize();
      $height = $entry->getGphotoHeight();
      $width = $entry->getGphotoWidth();
      $photoid = $entry->getGphotoId();
      $albumid = $entry->getGphotoAlbumId();
      
      echo "<h2>$summary</h2>\n";
      echo "<table><tr><td><img src=\"" . 
      $thumbnail[1]->url . "\"/></td>\n";
      echo "<td><span class=\"attr\">File</span>: $title 
      <br />\n";
      echo "<span class=\"attr\">Size</span>: $size bytes 
      ($height x $width) <br />\n";
      echo "<span class=\"attr\">Tags</span>: $tags 
      <br />\n";
      echo "<a href=\"delete.php?aid=$albumid&pid=$photoid\">
       delete photo</a></td></tr></table>\n";
    }
    ?>
    
    <a href="add.php">Add a new photo</a>
    <p/>
    
    <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="get">
      Search for photos containing:<br/>
      <input type="text" name="q" size="10"/><p/>
      <input type="submit" name="submit" value="Search"/>
    </form>

  </body>
</html>
        

그림 8은 Listing 12를 실행한 결과 예다.


그림 8. 앨범에 든 사진을 열거하는 웹 페이지
앨범에 든 사진을 열거하는 웹 페이지 

Listing 12에 있는 검색 폼을 제출하면 단순히 list.php가 다시 실행된다. 단지, 이 때는 조회 객체가 제공하는 setQuery() 메서드를 사용하여 사용자가 검색하려는 문자열을 요청 피드에 추가한다.

Listing 13에서 보듯이, add.php는 새 사진을 추가한다.


Listing 13: 사진 추가하기
            
<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Adding photos to an album</title>
    <style>
    body {
      font-family: Verdana;
    }
    li {
      border-bottom: solid black 1px;
      margin: 10px;
      padding: 2px;
      width: auto;
      padding-bottom: 20px;
    }
    h2 {
      color: red;
      text-decoration: none;
    }
    span.attr {
      font-weight: bolder;  
    }
    </style>
  </head>
  <body>
    <h1>Add Photo</h1>
    <?php if (!isset($_POST['submit'])) { ?>
    <form method="post" action="<?php 
    echo htmlentities($_SERVER['PHP_SELF']); ?>" enctype="multipart/form-data">
      Title: <br/>
      <input name="title" type="text" size="25" /><p/>
      File to upload: <br/>
      <input name="photofile" type="file" /><p/>
      Tags: <br/>
      <input name="tags" type="text" size="25" /><p/>
      <input name="submit" type="submit" value="Save" />
    </form>
    <?php
    } else {
      // 클래스를 올린다.
      require_once 'Zend/Loader.php';
      Zend_Loader::loadClass('Zend_Gdata');
      Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
      Zend_Loader::loadClass('Zend_Gdata_Photos');
      Zend_Loader::loadClass('Zend_Http_Client');
      
      // 서비스에 연결한다.
      $svc = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
      $user = "userid@gmail.com";
      $pass = "secret";
      $client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $svc);
      $gphoto = new Zend_Gdata_Photos($client);
      
      // 입력을 검증한다.
      if (empty($_POST['title'])) {
        die('ERROR: Missing title');
      } 
      
      // 입력을 검증한다.
      $title = htmlentities($_POST['title']);
      $tags = htmlentities($_POST['tags']);

      // 앨범 이름을 설정한다.
      $albumName = "France2008";

      // 사진 객체를 만든다.
      // 서버에 저장한다.
      try {
        $photo = $gphoto->newPhotoEntry();
        
        // 파일을 설정한다.
        $file = $gphoto->newMediaFileSource($_FILES['photofile']['tmp_name']);
        $file->setContentType("image/jpeg");
        $photo->setMediaSource($file);
        
        // 제목을 설정한다.
        $photo->setSummary($gphoto->newSummary($title));
        
        // 태그를 설정한다.
        $photo->mediaGroup = new Zend_Gdata_Media_Extension_MediaGroup();
        $keywords = new Zend_Gdata_Media_Extension_MediaKeywords();
        $keywords->setText($tags);
        $photo->mediaGroup->keywords = $keywords;
        
        // 앨범에 링크를 건다.
        $album = $gphoto->newAlbumQuery();
        $album->setUser($user);
        $album->setAlbumName($albumName);
        
        // 사진을 저장한다.
        $gphoto->insertPhotoEntry($photo, $album->getQueryUrl()); 
      } catch (Zend_Gdata_App_Exception $e) {
        echo "Error: " . $e->getResponse();
      }
      echo 'Photo successfully added!';
    }
    ?>
  </body>
</html>    
        

그림 9는 Listing 13을 실행한 결과 예다.


그림 9. 새 사진을 추가하는 웹 폼
새 사진을 추가하는 웹 폼 

delete.php 스크립트는 사진을 삭제한다. 인수는 앨범과 사진 ID로, list.php에서 GET 방식으로 받는다. delete.php는 앨범과 사진 ID로 사진을 찾은 후 해당 사진을 삭제한다. 코드는 Listing 14를 참조한다.


Listing 14: 사진 삭제하기
            
<?php
// 앨범과 사진 ID를 점검한다.
if (empty($_GET['aid']) || empty($_GET['pid'])) {
  die('ERROR: Missing input parameters');
} else{
  $aid = htmlentities($_GET['aid']);  
  $pid = htmlentities($_GET['pid']);  
}

// 클래스를 올린다.
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Gdata_Photos');
Zend_Loader::loadClass('Zend_Http_Client');

// 서비스에 연결한다.
$svc = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$user = "userid@gmail.com";
$pass = "secret";
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $svc);
$gphoto = new Zend_Gdata_Photos($client);

// 사진 항목을 얻는다.
// 항목을 삭제한다.
try {
  $photo = $gphoto->getPhotoEntry('http://picasaweb.google.com/data/
  entry/api/user/userid/albumid/' . $aid . '/photoid/' . $pid);
  $photo->delete();
} catch (Zend_Gdata_App_Exception $e) {
  echo "Error: " . $e->getResponse();
}
echo 'Photo successfully deleted!';
?>
        
저작자 표시
신고

'☆Develpoer > └ php' 카테고리의 다른 글

array_merge  (0) 2012.02.15
ob_start  (0) 2012.02.15
피카사 웹 앨범으로 PHP 응용 프로그램 개발하기  (0) 2011.12.28
PHP대용량 파일 업로드시 확인해야될 문제  (0) 2011.12.13
Migrating from PHP 5.2.x to PHP 5.3.x  (0) 2011.12.08
php5isapi.dll  (0) 2011.11.18