PageRenderTime 42ms CodeModel.GetById 19ms app.highlight 17ms RepoModel.GetById 2ms app.codeStats 0ms

/plugin/PBAPI/PBAPI.php

https://bitbucket.org/chamilo/chamilo-ext-repo-photobucket-dev/
PHP | 689 lines | 346 code | 63 blank | 280 comment | 65 complexity | 64d29b73d279f743f9ff5d98da4dc292 MD5 | raw file
  1<?php
  2/**
  3 * Photobucket API
  4 * Fluent interface for PHP5
  5 *
  6 * @author jhart
  7 * @package PBAPI
  8 *
  9 * @copyright Copyright (c) 2008, Photobucket, Inc.
 10 * @license http://www.opensource.org/licenses/mit-license.php The MIT License
 11 */
 12require_once dirname(__FILE__) . '/PBAPI/Exception.php';
 13/**
 14 * Load Exceptions
 15 */
 16/**
 17 * Load Response Exceptions
 18 */
 19require_once dirname(__FILE__) . '/PBAPI/Exception/Response.php';
 20
 21/**
 22 * PBAPI Class
 23 * Main class for Photobucket API interaction
 24 *
 25 * @package PBAPI
 26 */
 27class PBAPI
 28{
 29    
 30    /**
 31     * Request object holder
 32     *
 33     * @var PBAPI_Request
 34     */
 35    protected $request;
 36    /**
 37     * Response parser holder
 38     *
 39     * @var PBAPI_Response
 40     */
 41    protected $response;
 42    /**
 43     * Methods classes holder
 44     *
 45     * @var PBAPI_Methods
 46     */
 47    protected $methods;
 48    
 49    /**
 50     * current method stack
 51     *
 52     * @var array
 53     */
 54    protected $method_stack = array();
 55    /**
 56     * Current parameter set
 57     *
 58     * @var array key->value pairs
 59     */
 60    protected $params = array();
 61    /**
 62     * Current URI
 63     *
 64     * @var string
 65     */
 66    protected $uri;
 67    
 68    /**
 69     * Current username
 70     *
 71     * @var string
 72     */
 73    protected $username = '';
 74    
 75    /**
 76     * Flag to not reset after method call
 77     *
 78     * @var bool
 79     */
 80    protected $noReset = false;
 81    
 82    /**
 83     * Method validation map
 84     *
 85     * @static
 86     * @var array
 87     */
 88    static $method_validation_map;
 89
 90    /**
 91     * Class constructor
 92     * Sets up request, consumer and methods
 93     *
 94     * @param string $consumer_key OAuth consumer key (scid)
 95     * @param string $consumer_secret OAuth consumer secret (private key)
 96     * @param string $type [optional, default=determined] Request type (one of class names in PBAPI/Request/*)
 97     * @param string $subdomain [optional, default='api'] default subdomain to use in requests
 98     * @param string $default_format [optional, default='xml'] response format to receive from api
 99     * @param array $type_params [optional, default=none] Request class parameters
100     */
101    public function __construct($consumer_key, $consumer_secret, $type = null, $subdomain = 'api', $default_format = 'xml', $type_params = array())
102    {
103        $this->_loadMethodClass('base');
104        
105        $this->setRequest($type, $subdomain, $default_format, $type_params);
106        $this->setOAuthConsumer($consumer_key, $consumer_secret);
107    }
108
109    /////////////////////// Setup and Settings ///////////////////////
110    
111
112    /**
113     * Set OAuth Token
114     *
115     * @param string $token oauth token
116     * @param string $token_secret oauth secret
117     * @param string $username [optional, default=nochange] username associated with this token
118     * @return PBAPI $this Fluent reference to self
119     * @throws PBAPI_Exception on missing request
120     */
121    public function setOAuthToken($token, $token_secret, $username = '')
122    {
123        if ($this->request)
124            $this->request->setOAuthToken($token, $token_secret);
125        else
126            throw new PBAPI_Exception('Request missing - cannot set OAuth Token', $this);
127        
128        if ($username)
129            $this->username = $username;
130        return $this;
131    }
132
133    /**
134     * Get OAuth Token
135     *
136     * @throws PBAPI_Exception on missing request
137     */
138    public function getOAuthToken()
139    {
140        if ($this->request)
141            return $this->request->getOAuthToken();
142        else
143            throw new PBAPI_Exception('Request missing - cannot get OAuth Token', $this);
144    }
145
146    /**
147     * Set OAuth Consumer info
148     *
149     * @param string $consumer_key OAuth consumer key (scid)
150     * @param string $consumer_secret OAuth consumer secret (private key)
151     * @return PBAPI $this Fluent reference to self
152     * @throws PBAPI_Exception on missing request
153     */
154    public function setOAuthConsumer($consumer_key, $consumer_secret)
155    {
156        if ($this->request)
157            $this->request->setOAuthConsumer($consumer_key, $consumer_secret);
158        else
159            throw new PBAPI_Exception('Request missing - cannot set OAuth Token', $this);
160        
161        return $this;
162    }
163
164    /**
165     * Set current subdomain
166     *
167     * @param string $subdomain
168     * @return PBAPI $this Fluent reference to self
169     * @throws PBAPI_Exception on missing request
170     */
171    public function setSubdomain($subdomain)
172    {
173        if ($this->request)
174            $this->request->setSubdomain($subdomain);
175        else
176            throw new PBAPI_Exception('Request missing - cannot set Subdomain', $this);
177        
178        return $this;
179    }
180
181    /**
182     * Get current subdomain
183     */
184    public function getSubdomain()
185    {
186        if ($this->request)
187            return $this->request->getSubdomain();
188        else
189            throw new PBAPI_Exception('Request missing - cannot get Subdomain', $this);
190    }
191
192    /**
193     * Get oauth token username
194     */
195    public function getUsername()
196    {
197        return $this->username;
198    }
199
200    /**
201     * Set response parser
202     *
203     * @param string $type [optional, default=none] type of response parser (one of PBAPI/Response/*)
204     * @param array $params [optional, default=none] parameters to set up parser
205     * @return PBAPI $this Fluent reference to self
206     */
207    public function setResponseParser($type = null, $params = array())
208    {
209        $class = 'PBAPI_Response_' . $type;
210        if (! class_exists($class))
211            require ('PBAPI/Response/' . $type . '.php');
212        $this->response = new $class($params);
213        
214        if (! $this->response)
215            throw new PBAPI_Exception('Could not get Response Parser', $this);
216        if (! $this->request)
217            throw new PBAPI_Exception('Request missing - cannot set OAuth Token', $this);
218        
219        $this->request->setDefaultFormat($this->response->getFormat());
220        return $this;
221    }
222
223    /**
224     * Set request method
225     *
226     * @param string $type [optional, default=determined] Request type (one of class names in PBAPI/Request/*)
227     * @param string $subdomain [optional, default='api'] default subdomain to use in requests
228     * @param string $default_format [optional, default='xml'] response format to receive from api
229     * @param array $type_params [optional, default=none] Request class parameters
230     * @return PBAPI $this Fluent reference to self
231     */
232    public function setRequest($type = null, $subdomain = 'api', $default_format = 'xml', $request_params = array())
233    {
234        if (! $type)
235            $type = self :: _detectRequestStrategy();
236        $class = 'PBAPI_Request_' . $type;
237        if (! class_exists($class))
238            require ('PBAPI/Request/' . $type . '.php');
239        $this->request = new $class($subdomain, $default_format, $request_params);
240        return $this;
241    }
242
243    /**
244     * Attempt to detect request strategy and set the type
245     *
246     * @return string
247     */
248    protected static function _detectRequestStrategy()
249    {
250        if (function_exists('curl_init'))
251            return 'curl';
252        if (ini_get('allow_url_fopen'))
253            return 'fopenurl';
254    }
255
256    /**
257     * Reset current data
258     *
259     * @param bool $uri [optional] reset URI data
260     * @param bool $methods [optional] reset method data (current method depth)
261     * @param bool $params [optional] reset all parameters
262     * @param bool $auth [optional] reset auth token
263     * @return PBAPI $this Fluent reference to self
264     */
265    public function reset($uri = true, $methods = true, $params = true, $auth = false)
266    {
267        if ($uri)
268            $this->uri = null;
269        if ($methods)
270        {
271            $this->methods->_reset();
272            $this->method_stack = array();
273        }
274        if ($params)
275            $this->params = array();
276        if ($auth && $this->request)
277            $this->resetOAuthToken();
278        return $this;
279    }
280
281    /**
282     * Set No Reset Flag
283     *
284     * @param bool $set
285     * @return PBAPI $this Fluent reference to self
286     */
287    public function setNoReset($set)
288    {
289        $this->noReset = $set;
290        return $this;
291    }
292
293    /////////////////////// Requests and Responses ///////////////////////
294    
295
296    /**
297     * Get current parameters
298     *
299     * @return array current parameter key->values
300     */
301    public function getParams()
302    {
303        return $this->params;
304    }
305
306    /**
307     * Get parsed response (from response parser)
308     *
309     * @param bool $onlycontent only return 'content' of response
310     * @return mixed
311     * @throws PBAPI_Exception on no response parser
312     * @throws PBAPI_Exception_Response on response exception
313     */
314    public function getParsedResponse($onlycontent = false)
315    {
316        if (! $this->response)
317            throw new PBAPI_Exception('No response parser set up', $this);
318        
319        try
320        {
321            return $this->response->parse(trim($this->response_string), $onlycontent);
322        }
323        catch (PBAPI_Exception_Response $e)
324        {
325            //set core into exception
326            throw new PBAPI_Exception_Response($e->getMessage(), $e->getCode(), $this);
327        }
328    }
329
330    /**
331     * Get raw response string
332     *
333     * @return string
334     */
335    public function getResponseString()
336    {
337        return $this->response_string;
338    }
339
340    /**#@+
341     * Forward current set up request to the request method and get back the response
342     *
343     * @return PBAPI $this Fluent reference to self
344     */
345    public function get()
346    {
347        $this->_validateRequest('get');
348        $this->_setResponse($this->request->get($this->uri, $this->params));
349        if (! $this->noReset)
350            $this->reset();
351        return $this;
352    }
353
354    public function post()
355    {
356        $this->_validateRequest('post');
357        $this->_setResponse($this->request->post($this->uri, $this->params));
358        if (! $this->noReset)
359            $this->reset();
360        return $this;
361    }
362
363    public function put()
364    {
365        $this->_validateRequest('put');
366        $this->_setResponse($this->request->put($this->uri, $this->params));
367        if (! $this->noReset)
368            $this->reset();
369        return $this;
370    }
371
372    public function delete()
373    {
374        $this->_validateRequest('delete');
375        $this->_setResponse($this->request->delete($this->uri, $this->params));
376        if (! $this->noReset)
377            $this->reset();
378        return $this;
379    }
380
381    /**#@-*/
382    
383    /**
384     * Load and set the current OAuth token from the last response string
385     *
386     * @param bool $subdomain true if you want to also set the current default call subdomain to what is in the response.
387     * @return PBAPI $this Fluent reference to self
388     */
389    public function loadTokenFromResponse($subdomain = true)
390    {
391        $string = trim($this->response_string);
392        $params = array();
393        
394        parse_str($string, $params);
395        if (empty($params) || empty($params['oauth_token']) || empty($params['oauth_token_secret']))
396        {
397            throw new PBAPI_Exception('Token and Token Secret returned in response');
398        }
399        
400        $username = (! empty($params['username'])) ? $params['username'] : '';
401        $this->setOAuthToken($params['oauth_token'], $params['oauth_token_secret'], $username);
402        if ($subdomain && ! empty($params['subdomain']))
403        {
404            $this->setSubdomain($params['subdomain']);
405        }
406        return $this;
407    }
408
409    /**
410     * Go to Redirect URL
411     * does actual header()
412     *
413     * @param string $type [login|logout|...]
414     * @param string $extra [optional] set 'extra' parameter
415     * @throws PBAPI_Exception on invalid redirect
416     */
417    public function goRedirect($type = null, $extra = null)
418    {
419        if (strpos($type, 'http://') !== 0)
420        {
421            switch ($type)
422            {
423                case 'login' :
424                    $this->request->redirectLogin($extra);
425                case 'logout' :
426                    $this->request->redirectLogout($extra);
427                default :
428                    throw new PBAPI_Exception('Invalid redirect', $this);
429            }
430        }
431        else
432        {
433            if ($extra)
434            {
435                $sep = (strpos($type, '?')) ? '&' : '?';
436                $url = $type . $sep . 'extra=' . $extra;
437            }
438            else
439            {
440                $url = $type;
441            }
442            header('Location: ' . $url);
443            exit();
444        }
445    }
446
447    /////////////////////// Inter Class 'Private' Methods ///////////////////////
448    
449
450    /**
451     * Set a parameter
452     *
453     * @param string $name
454     * @param string $value
455     * @return PBAPI $this Fluent reference to self
456     */
457    public function _setParam($name, $value)
458    {
459        $this->params[$name] = $value;
460        return $this;
461    }
462
463    /**
464     * Set a list of parameters
465     *
466     * @param array $pairs parameters as key=>value (allowing empty)
467     * @return PBAPI $this Fluent reference to self
468     */
469    public function _setParamList($pairs)
470    {
471        if (! $pairs)
472            return $this;
473        foreach ($pairs as $name => $value)
474        {
475            $this->_setParam($name, $value);
476        }
477        return $this;
478    }
479
480    /**
481     * Set current URI
482     *
483     * @param string $uri uri string to set, sprintf format
484     * @param array $replacements [optional, default=none] if uri is sprintf string, replacements from this array in array order
485     * @return PBAPI $this Fluent reference to self
486     */
487    public function _setUri($uri, $replacements = null)
488    {
489        if ($replacements !== null && ! is_array($replacements))
490            $replacements = array($replacements);
491        if ($replacements !== null)
492        {
493            $replacements = array_map('urlencode', $replacements);
494            $this->uri = vsprintf($uri, $replacements);
495        }
496        else
497            $this->uri = $uri;
498        return $this;
499    }
500
501    /**
502     * Append more to the current uri
503     *
504     * @param string $uri uri string to set, sprintf format
505     * @param array $replacements [optional, default=none] if uri is sprintf string, replacements from this array in array order
506     * @return PBAPI $this Fluent reference to self
507     */
508    public function _appendUri($uri, $replacements = null)
509    {
510        if ($replacements !== null && ! is_array($replacements))
511            $replacements = array($replacements);
512        if ($replacements !== null)
513        {
514            $replacements = array_map('urlencode', $replacements);
515            $this->uri .= vsprintf($uri, $replacements);
516        }
517        else
518            $this->uri .= $uri;
519        return $this;
520    }
521
522    /**
523     * Load a method class
524     *
525     * @param string $name Method class name (one of PBAPI/Methods/*)
526     * @return PBAPI_Methods
527     */
528    public function _loadMethodClass($name)
529    {
530        $class = 'PBAPI_Methods_' . $name;
531        if (! class_exists($class))
532            require_once (dirname(__FILE__) . '/PBAPI/Methods/' . $name . '.php');
533        $classObj = new $class($this);
534        return $this->_setMethods($classObj);
535    }
536
537    /**
538     * Set Methods class
539     *
540     * @param PBAPI_Methods $class class instance
541     * @return PBAPI $this Fluent reference to self
542     */
543    public function _setMethods($class)
544    {
545        $this->methods = $class;
546        return $this;
547    }
548
549    /**
550     * Get parameters currently in obj
551     *
552     * @return array key->value
553     */
554    public function _getParams()
555    {
556        return $this->params;
557    }
558
559    /**
560     * Get method stack - this is the level list of the method
561     *
562     * @return array methods list (in call order)
563     */
564    public function _getMethodStack()
565    {
566        return $this->method_stack;
567    }
568
569    /**
570     * Set the current response string
571     *
572     * @param string $string
573     * @return PBAPI $this Fluent reference to self
574     */
575    protected function _setResponse($string)
576    {
577        $this->response_string = $string;
578        return $this;
579    }
580
581    /**
582     * Validate Request (as currently set)
583     *
584     * $dt = syck_load(file_get_contents('api-defs.yml'));
585     * file_put_contents('methods.dat', serialize($dt));
586     *
587     * @param string $method HTTP method to check against
588     * @return PBAPI $this Fluent reference to self
589     * @throws PBAPI_Exception method or parameters don't match presets
590     */
591    protected function _validateRequest($method)
592    {
593        //get proper map
594        $map = $this->_loadMethodValidationMap();
595        
596        //fixup stack
597        $stack = $this->method_stack;
598        if (empty($stack[1]))
599            $stack[1] = '_default';
600        
601     //get method
602        $val_methods = $map[$stack[0]][$stack[1]];
603        if (! $val_methods || ! array_key_exists($method, $val_methods))
604            throw new PBAPI_Exception('invalid method: ' . $method, $this);
605        
606     //get parameters
607        $val_params = $val_methods[$method];
608        if ($val_params)
609        {
610            //look for unknown parameters (if parameters are specified)
611            $unknowns = array_diff_key($this->params, $val_params);
612            if (count($unknowns))
613                throw new PBAPI_Exception('unknown parameters: ' . implode(', ', array_keys($unknowns)), $this);
614            
615     //look for missing required parameters
616            $missing = array_diff_key($val_params, $this->params);
617            if (count($missing))
618            {
619                foreach ($missing as $key => $val)
620                {
621                    if ($val != 'required')
622                        unset($missing[$key]);
623                    if ($key == 'aid' || $key == 'mid' || $key == 'uid' || $key == 'tagid') //todo somehow do this better
624                        unset($missing[$key]); //also skip stuff we're catching already
625                }
626                if (count($missing))
627                    throw new PBAPI_Exception('missing required parameters: ' . implode(', ', array_keys($missing)), $this);
628            }
629        }
630        return $this;
631    }
632
633    /**
634     * Load validation map from data file
635     * Loads from ./PBAPI/data/methods.dat - a php serialize() file.
636     * The .yml file in the same directory is the 'source' of that dat file.
637     *
638     * @return array validation map from data file
639     */
640    protected function _loadMethodValidationMap()
641    {
642        if (! self :: $method_validation_map)
643        {
644            $path = dirname(__FILE__) . '/PBAPI/data/methods.dat';
645            self :: $method_validation_map = unserialize(file_get_contents($path));
646            if (! self :: $method_validation_map)
647                throw new PBAPI_Exception('Could not load method map', $this);
648        }
649        return self :: $method_validation_map;
650    }
651
652    /////////////////////// Magics ///////////////////////
653    
654
655    /**
656     * Magic function to forward other calls to the Methods
657     * This is the meat of the API, really
658     *
659     * @param string $name function name
660     * @param array $args argument array
661     * @return PBAPI $this Fluent reference to self
662     */
663    public function __call($name, $args)
664    {
665        if (empty($args))
666        {
667            $this->methods->$name();
668        }
669        else 
670            if (! empty($args[0]) && empty($args[1]))
671            {
672                $this->methods->$name($args[0]);
673            }
674            else 
675                if (! empty($args[0]) && ! empty($args[1]))
676                {
677                    $this->methods->$name($args[0], $args[1]);
678                }
679                else
680                {
681                    //not currently used, but for forward compatibility
682                    call_user_func_array(array($this->methods, $name), $args);
683                }
684        
685        $this->method_stack[] = $name;
686        return $this;
687    }
688
689}