').appendTo("body"),b=a.children(),
+b=b.innerWidth()-b.height(99).innerWidth();a.remove();return b});if(f.support.fixedPosition===r){var a=f.support,d=f('').appendTo("body"),e=20===d[0].offsetTop||15===d[0].offsetTop;d.remove();a.fixedPosition=e}f.extend(b.defaults,{scrollbarWidth:f.scrollbarWidth(),fixed:f.support.fixedPosition,parent:f("body")})})})(window,document,jQuery);
\ No newline at end of file
diff --git a/web/content/scripts/imagehosting.js b/web/content/scripts/imagehosting.js
new file mode 100644
index 0000000..1b8a16d
--- /dev/null
+++ b/web/content/scripts/imagehosting.js
@@ -0,0 +1,99 @@
+// used to remember last clicked image id
+var lastClickedImageId; // dont kill me, Im too global.
+
+// builds image block used to present images - favorite or just random
+function buildImageBlocks(jsonData, isFavorite) {
+ var content = '';
+ $.each(jsonData, function(key, val) {
+ content += '
';
+ });
+ return content;
+}
+
+// loads generated images from the server side
+function loadRandomImages(data) {
+ var imageBlock = buildImageBlocks(data, false);
+ $("#randomStatus").hide();
+ $('#randomList').append(imageBlock);
+}
+
+// loads favorite images from the server side
+function loadFavoriteImages(data) {
+ var imageBlock = buildImageBlocks(data, true);
+ $("#favoriteStatus").hide();
+ $('#favoriteList').append(imageBlock);
+}
+
+// send ajax request to the given url and tries to load received daata
+function generateImages(ajaxPath) {
+ $("#randomList").empty();
+ $("#randomStatus").show().text("Loading new images...");
+ $.getJSON(ajaxPath, loadRandomImages).fail(function () {
+ $("#randomStatus").show().text("Error occurred while loading!");
+ });
+}
+
+// close dialog, update image's description on client and on the server
+function sendDescription(e){
+ e.preventDefault();
+ $.fancybox.close();
+
+ $("img#" + lastClickedImageId).attr("title", $('#descriptionText').val());
+ $.post("api/favorite/" + lastClickedImageId + "/description/add/", { 'text': $('#descriptionText').val() });
+}
+
+// bind events and load init data
+function initDocument() {
+ $("#flikrGenerate").click(function() { generateImages("api/flikr/") });
+ $("#instagramGenerate").click(function() { generateImages("api/instagram/") });
+ $('#descriptionForm').submit(sendDescription);
+ $(".addDescription").fancybox();
+
+ $.getJSON("api/favorite/", loadFavoriteImages).fail(
+ function () {
+ $("#randomStatus").show().text("Error occurred while loading favorite images!");
+ });
+ $.getJSON("api/", loadRandomImages);
+}
+
+// when clicked addDescription button - storage the clicked image id to use it in the future
+$(document.body).on('click','a.addDescription', function(){
+ var img = $(this).parent().find("img");
+ lastClickedImageId = img.attr("id");
+ $('#descriptionText').val(img.attr("title"));
+});
+
+// when clicked setFavorite link - remove from the random list and move to favorite list,
+// decorate with favorite image specific links and send ajax request to the server
+$(document.body).on('click','a.setFavorite', function() {
+ var imageBlock = $(this).parent();
+ imageBlock.appendTo('#favoriteList');
+ imageBlock.find('a').attr('class', 'removeFavorite').text('remove');
+ imageBlock.append(' add description');
+ $.getJSON("api/favorite/add/" + imageBlock.find("img").attr("id"));
+});
+
+// when clicked removeFavorite link - send ajax request to the server and remove block from the screen
+$(document.body).on('click','a.removeFavorite', function() {
+ $("#favoriteStatus").hide();
+ var imageBlock = $(this).parent();
+ $.getJSON("api/favorite/remove/" + imageBlock.find("img").attr("id"));
+ imageBlock.remove();
+});
+
+// turn on link hover on IE6 and IE7
+$(document.body).on('hover','a', function(){
+ $(this).toggleClass('hover');
+});
+
+// initialize the document
+$(document).ready(initDocument);
\ No newline at end of file
diff --git a/web/content/styles/style.css b/web/content/styles/style.css
new file mode 100644
index 0000000..2b46bf8
--- /dev/null
+++ b/web/content/styles/style.css
@@ -0,0 +1,125 @@
+*{
+ padding: 0;
+ margin: 0;
+}
+
+body {
+ background: url("../images/body-bg.png") repeat #e7e7e7;
+ font-family: Verdana, Helvetica, sans-serif;
+}
+
+ul, li, a {
+ cursor: pointer;
+ text-decoration: none;
+ color: #666;
+}
+
+a:hover {
+ color: #333;
+}
+
+hr {
+ background: url("../images/hr.png");
+ height: 1px;
+ border: none;
+ margin-top: 20px;
+ margin-bottom: 20px;
+}
+
+.clear {
+ clear: both;
+}
+/*---------------------------------------*/
+
+#bodydiv {
+ background: url("../images/highlight-bg.jpg") no-repeat top center;
+ margin: auto;
+ width: 980px;
+}
+
+#header {
+ padding-top: 50px;
+}
+
+#header h1 {
+ text-shadow: 2px 1px 0 #FFF;
+ font-size: 48px;
+ color: #303030;
+ font-weight: 900;
+ line-height: 1.5;
+}
+
+#header h3 {
+ text-shadow: 1px 1px 0 #FFF;
+ color: #AAA;
+ font-weight: normal;
+}
+
+#content h2 {
+ padding: 10px 0 10px 0;
+ font-size: 22px;
+ color: #aaa;
+}
+
+#content h4 {
+ padding: 10px 0 10px 0;
+ color: #d5000d;
+}
+
+/*---------------------------------------*/
+
+.setFavorite, .removeFavorite {
+ margin-left: 23px;
+ padding: 5px 0 10px 0;
+ font-size: 16px;
+}
+
+.removeFavorite {
+ padding-left: 35px;
+ background: url(../images/remove.png) no-repeat;
+}
+
+.imageBlock {
+ width: 152px;
+ height: 200px;
+ float: left;
+ margin: 0 30px 45px 10px;
+}
+
+.imageBlock img {
+ margin: 18px 18px 10px 18px;
+ border: solid 3px #ecefef;
+}
+
+#generateButtons {
+ clear: both;
+ text-align: center;
+ margin-bottom: 20px;
+}
+
+#generateButtons button {
+ width: 200px;
+ height: 50px;
+ margin: 25px;
+ color: #303030;
+ font-size: 16px;
+ border: solid 1px #aaa;
+ cursor: pointer;
+ box-shadow: 0px 1px 5px 1px #b7c3c8;
+ border-radius: 25px;
+}
+
+#descriptionPanel form {
+ text-align: center;
+}
+
+#descriptionPanel textarea {
+ padding: 10px;
+ width: 200px;
+ height: 50px;
+}
+
+#descriptionPanel input[type="submit"] {
+ padding: 12px 10px 12px 10px;
+
+}
\ No newline at end of file
diff --git a/web/doc/ImageHostingService.txt b/web/doc/ImageHostingService.txt
new file mode 100644
index 0000000..1dba560
--- /dev/null
+++ b/web/doc/ImageHostingService.txt
@@ -0,0 +1,34 @@
+name: ImageHostingService
+author: Umed Khudoiberdiev
+description:
+
+Image Hosting Service provides functionality to generate images from external services (Flikr, Instagram),
+storage generated image links in the database, allows to set them as favorite and add custom user descriptions.
+
+application infrastructure:
+
+/component - contains system components (each component dependency free);
+/content - client side content, styles, scripts and other client resources;
+/lib - contains third party php libraries;
+/module/imagehosting - contains classes according to specific module (ImageHostingService);
+/doc - system's documentation resources;
+
+/api.php - handles api calls to the application's components;
+/config.php - holds application configuration;
+/index.html - provides user startup interface;
+/.htaccess - provides basic address rewrites for api.php file;
+/README - just read it.
+
+Image Hosting Service API:
+
+/api/ Get list of random images
+/api/flikr/ Generate new random images from flikr
+/api/instagram/ Generate new random images from instagram
+/api/favorite/ Get list of favorite images
+/api/favorite/add/{id}/ Add new favorite image with id = {id}
+/api/favorite/remove/{id}/ Remove favorite image with id = {id}
+
+/api/favorite/{id}/description/add/?text={text} Add description {text} to the favorite image with id = {id}
+ Please note that {text} param should be send by POST method
+
+/api/favorite/{id}/description/remove/ Remove description from the favorite image with id = {id}
\ No newline at end of file
diff --git a/web/index.html b/web/index.html
new file mode 100644
index 0000000..1db7376
--- /dev/null
+++ b/web/index.html
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+ Image Hosting Service
+
+
+
+
+
Image Hosting Service
+
View random images, save your favorite!
+
+
+
+
+
Favorite Images
+
There are no favorite images yet
+
+
+
+
+
+
+
Random Images
+
There are no images yet. Press generate button to generate new images
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Description will appear on the hover of the image
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/web/lib/flikr_api/README.txt b/web/lib/flikr_api/README.txt
new file mode 100644
index 0000000..8524ed1
--- /dev/null
+++ b/web/lib/flikr_api/README.txt
@@ -0,0 +1,215 @@
+phpFlickr Class 3.0
+Written by Dan Coulter (dancoulter@users.sourceforge.net)
+Project Homepage: http://www.phpflickr.com/
+Google Code Project Page: http://code.google.com/p/phpflickr/
+Released under GNU Lesser General Public License (http://www.gnu.org/copyleft/lgpl.html)
+For more information about the class and upcoming tools and applications using it,
+visit http://www.phpflickr.com/ or http://code.google.com/p/phpflickr/
+
+If you are interested in hiring me for a project (involving phpFlickr
+or not), feel free to email me.
+
+Installation instructions:
+1. Copy the files from the installation package into a folder on your
+ server. They need to be readible by your web server. You can put
+ them into an include folder defined in your php.ini file, if you
+ like, though it's not required.
+
+2. All you have to do now is include the file in your PHP scripts and
+ create an instance. For example:
+ $f = new phpFlickr();
+
+ The constructor has three arguments:
+ A. $api_key - This is the API key given to you by flickr.com. This
+ argument is required and you can get an API Key at:
+ http://www.flickr.com/services/api/key.gne
+
+ B. $secret - The "secret" is optional because is not required to
+ make unauthenticated calls, but is absolutely required for the
+ new authentication API (see Authentication section below). You
+ will get one assigned alongside your api key.
+
+ C. $die_on_error - This takes a boolean value and determines
+ whether the class will die (aka cease operation) if the API
+ returns an error statement. It defaults to false. Every method
+ will return false if the API returns an error. You can access
+ error messages using the getErrorCode() and getErrorMsg()
+ methods.
+
+3. All of the API methods have been implemented in my class. You can
+ see a full list and documentation here:
+ http://www.flickr.com/services/api/
+ To call a method, remove the "flickr." part of the name and replace
+ any periods with underscores. For example, instead of
+ flickr.photos.search, you would call $f->photos_search() or instead
+ of flickr.photos.licenses.getInfo, you would call
+ $f->photos_licenses_getInfo() (yes, it is case sensitive).
+
+ All functions have their arguments implemented in the list order on
+ their documentation page (a link to which is included with each
+ method in the phpFlickr clasS). The only exceptions to this are
+ photos_search(), photos_getWithoutGeodata() and
+ photos_getWithoutGeodata() which have so many optional arguments
+ that it's easier for everyone if you just have to pass an
+ associative array of arguments. See the comment in the
+ photos_search() definition in phpFlickr.php for more information.
+
+
+
+Authentication:
+ As of this release of the phpFlickr class there is only one authentication method
+ available to the API. This method is somewhat complex, but is far more secure and
+ allows your users to feel a little safer authenticating to your application. You'll
+ no longer have to ask for their username and password.
+
+ Authentication API - http://www.flickr.com/services/api/auth.spec.html
+
+ I know how complicated this API looks at first glance, so I've tried to
+ make this as transparent to the coding process. I'll go through the steps
+ you'll need to use this. Both the auth.php and getToken.php file will
+ need your API Key and Secret entered before you can use them.
+
+ To have end users authenticate their accounts:
+ First, setup a callback script. I've included a callback script that
+ is pretty flexible. You'll find it in the package entitled "auth.php".
+ You'll need to go to flickr and point your api key to this file as the
+ callback script. Once you've done this, on any page that you want to
+ require the end user end user to authenticate their flickr account to
+ your app, just call the phpFlickr::auth() function with whatever
+ permission you need to use.
+ For example:
+ $f->auth("write");
+ The three permissions are "read", "write" and "delete". The function
+ defaults to "read", if you leave it blank.
+
+ Calling this function will send the user's browser to Flickr's page to
+ authenticate to your app. Once they have logged in, it will bounce
+ them back to your callback script which will redirect back to the
+ original page that you called the auth() function from after setting
+ a session variable to save their authentication token. If that session
+ variable exists, calling the auth() function will return the permissions
+ that the user granted your app on the Flickr page instead of redirecting
+ to an external page.
+
+ To authenticate the app to your account to show your private pictures (for example)
+ This method will allow you to have the app authenticate to one specific
+ account, no matter who views your website. This is useful to display
+ private photos or photosets (among other things).
+
+ *Note*: The method below is a little hard to understand, so I've setup a tool
+ to help you through this: http://www.phpflickr.com/tools/auth/.
+
+ First, you'll have to setup a callback script with Flickr. Once you've
+ done that, edit line 12 of the included getToken.php file to reflect
+ which permissions you'll need for the app. Then browse to the page.
+ Once you've authorized the app with Flickr, it'll send you back to that
+ page which will give you a token which will look something like this:
+ 1234-567890abcdef1234
+ Go to the file where you are creating an instance of phpFlickr (I suggest
+ an include file) and after you've created it set the token to use:
+ $f->setToken("");
+ This token never expires, so you don't have to worry about having to
+ login periodically.
+
+
+Using Caching:
+ Caching can be very important to a project. Just a few calls to the Flickr API
+ can take long enough to bore your average web user (depending on the calls you
+ are making). I've built in caching that will access either a database or files
+ in your filesystem. To enable caching, use the phpFlickr::enableCache() function.
+ This function requires at least two arguments. The first will be the type of
+ cache you're using (either "db" or "fs")
+
+ 1. If you're using database caching, you'll need to supply a PEAR::DB connection
+ string. For example:
+ $flickr->enableCache("db", "mysql://user:password@server/database");
+ The third (optional) argument is expiration of the cache in seconds (defaults
+ to 600). The fourth (optional) argument is the table where you want to store
+ the cache. This defaults to flickr_cache and will attempt to create the table
+ if it does not already exist.
+
+ 2. If you're using filesystem caching, you'll need to supply a folder where the
+ web server has write access. For example:
+ $flickr->enableCache("fs", "/var/www/phpFlickrCache");
+ The third (optional) argument is, the same as in the Database caching, an
+ expiration in seconds for the cache.
+ Note: filesystem caching will probably be slower than database caching. I
+ haven't done any tests of this, but if you get large amounts of calls, the
+ process of cleaning out old calls may get hard on your server.
+
+ You may not want to allow the world to view the files that are created during
+ caching. If you want to hide this information, either make sure that your
+ permissions are set correctly, or disable the webserver from displaying
+ *.cache files. In Apache, you can specify this in the configuration files
+ or in a .htaccess file with the following directives:
+
+
+ Deny from all
+
+
+ Alternatively, you can specify a directory that is outside of the web server's
+ document root.
+
+Uploading
+ Uploading is pretty simple. Aside from being authenticated (see Authentication
+ section) the very minimum that you'll have to pass is a path to an image file on
+ your php server. You can do either synchronous or asynchronous uploading as follows:
+ synchronous: sync_upload("photo.jpg");
+ asynchronous: async_upload("photo.jpg");
+
+ The basic difference is that synchronous uploading waits around until Flickr
+ processes the photo and returns a PhotoID. Asynchronous just uploads the
+ picture and gets a "ticketid" that you can use to check on the status of your
+ upload. Asynchronous is much faster, though the photoid won't be instantly
+ available for you. You can read more about asynchronous uploading here:
+ http://www.flickr.com/services/api/upload.async.html
+
+ Both of the functions take the same arguments which are:
+ Photo: The path of the file to upload.
+ Title: The title of the photo.
+ Description: A description of the photo. May contain some limited HTML.
+ Tags: A space-separated list of tags to apply to the photo.
+ is_public: Set to 0 for no, 1 for yes.
+ is_friend: Set to 0 for no, 1 for yes.
+ is_family: Set to 0 for no, 1 for yes.
+
+Replacing Photos
+ Flickr has released API support for uploading a replacement photo. To use this
+ new method, just use the "replace" function in phpFlickr. You'll be required
+ to pass the file name and Flickr's photo ID. You need to authenticate your script
+ with "write" permissions before you can replace a photo. The arguments are:
+ Photo: The path of the file to upload.
+ Photo ID: The numeric Flickr ID of the photo you want to replace.
+ Async (optional): Set to 0 for a synchronous call, 1 for asynchronous.
+ If you use the asynchronous call, it will return a ticketid instead
+ of photoid.
+
+Other Notes:
+ 1. Many of the methods have optional arguments. For these, I have implemented
+ them in the same order that the Flickr API documentation lists them. PHP
+ allows for optional arguments in function calls, but if you want to use the
+ third optional argument, you have to fill in the others to the left first.
+ You can use the "NULL" value (without quotes) in the place of an actual
+ argument. For example:
+ $f->groups_pools_getPhotos($group_id, NULL, NULL, 10);
+ This will get the first ten photos from a specific group's pool. If you look
+ at the documentation, you will see that there is another argument, "page". I've
+ left it off because it appears after "per_page".
+ 2. Some people will need to ues phpFlickr from behind a proxy server. I've
+ implemented a method that will allow you to use an HTTP proxy for all of your
+ traffic. Let's say that you have a proxy server on your local server running
+ at port 8181. This is the code you would use:
+ $f = new phpFlickr("[api key]");
+ $f->setProxy("localhost", "8181");
+ After that, all of your calls will be automatically made through your proxy server.
+
+
+That's it! Enjoy the class. Check out the project page (listed above) for updates
+and news. I plan to implement file uploads and functions to aggregate data from
+several different methods for easier use in a web application. Thanks for your
+interest in this project!
+
+ Please email me if you have any questions or problems. You'll find my email
+ at the top of this file.
+
+
diff --git a/web/lib/flikr_api/auth.php b/web/lib/flikr_api/auth.php
new file mode 100644
index 0000000..0cee4dc
--- /dev/null
+++ b/web/lib/flikr_api/auth.php
@@ -0,0 +1,38 @@
+auth($permissions, false);
+ } else {
+ $f->auth_getToken($_GET['frob']);
+ }
+
+ if (empty($redirect)) {
+ header("Location: " . $default_redirect);
+ } else {
+ header("Location: " . $redirect);
+ }
+
+?>
\ No newline at end of file
diff --git a/web/lib/flikr_api/example.php b/web/lib/flikr_api/example.php
new file mode 100644
index 0000000..8b409b4
--- /dev/null
+++ b/web/lib/flikr_api/example.php
@@ -0,0 +1,30 @@
+" with one provided
+ * by Flickr: http://www.flickr.com/services/api/key.gne
+ */
+
+require_once("phpFlickr.php");
+$f = new phpFlickr("");
+
+$recent = $f->photos_getRecent();
+
+foreach ($recent['photo'] as $photo) {
+ $owner = $f->people_getInfo($photo['owner']);
+ echo "";
+ echo $photo['title'];
+ echo " Owner: ";
+ echo "";
+ echo $owner['username'];
+ echo " ";
+}
+?>
diff --git a/web/lib/flikr_api/getToken.php b/web/lib/flikr_api/getToken.php
new file mode 100644
index 0000000..1d232e4
--- /dev/null
+++ b/web/lib/flikr_api/getToken.php
@@ -0,0 +1,19 @@
+", "");
+
+ //change this to the permissions you will need
+ $f->auth("read");
+
+ echo "Copy this token into your code: " . $_SESSION['phpFlickr_auth_token'];
+
+?>
\ No newline at end of file
diff --git a/web/lib/flikr_api/phpFlickr.php b/web/lib/flikr_api/phpFlickr.php
new file mode 100644
index 0000000..df9d7d7
--- /dev/null
+++ b/web/lib/flikr_api/phpFlickr.php
@@ -0,0 +1,1805 @@
+api_key = $api_key;
+ $this->secret = $secret;
+ $this->die_on_error = $die_on_error;
+ $this->service = "flickr";
+
+ //Find the PHP version and store it for future reference
+ $this->php_version = explode("-", phpversion());
+ $this->php_version = explode(".", $this->php_version[0]);
+ }
+
+ function enableCache ($type, $connection, $cache_expire = 600, $table = 'flickr_cache') {
+ // Turns on caching. $type must be either "db" (for database caching) or "fs" (for filesystem).
+ // When using db, $connection must be a PEAR::DB connection string. Example:
+ // "mysql://user:password@server/database"
+ // If the $table, doesn't exist, it will attempt to create it.
+ // When using file system, caching, the $connection is the folder that the web server has write
+ // access to. Use absolute paths for best results. Relative paths may have unexpected behavior
+ // when you include this. They'll usually work, you'll just want to test them.
+ if ($type == 'db') {
+ if ( preg_match('|mysql://([^:]*):([^@]*)@([^/]*)/(.*)|', $connection, $matches) ) {
+ //Array ( [0] => mysql://user:password@server/database [1] => user [2] => password [3] => server [4] => database )
+ $db = mysql_connect($matches[3], $matches[1], $matches[2]);
+ mysql_select_db($matches[4], $db);
+
+ /*
+ * If high performance is crucial, you can easily comment
+ * out this query once you've created your database table.
+ */
+ mysql_query("
+ CREATE TABLE IF NOT EXISTS `$table` (
+ `request` CHAR( 35 ) NOT NULL ,
+ `response` MEDIUMTEXT NOT NULL ,
+ `expiration` DATETIME NOT NULL ,
+ INDEX ( `request` )
+ ) TYPE = MYISAM
+ ", $db);
+
+ $result = mysql_query("SELECT COUNT(*) FROM $table", $db);
+ $result = mysql_fetch_row($result);
+ if ( $result[0] > $this->max_cache_rows ) {
+ mysql_query("DELETE FROM $table WHERE expiration < DATE_SUB(NOW(), INTERVAL $cache_expire second)", $db);
+ mysql_query('OPTIMIZE TABLE ' . $this->cache_table, $db);
+ }
+ $this->cache = 'db';
+ $this->cache_db = $db;
+ $this->cache_table = $table;
+ }
+ } elseif ($type == 'fs') {
+ $this->cache = 'fs';
+ $connection = realpath($connection);
+ $this->cache_dir = $connection;
+ if ($dir = opendir($this->cache_dir)) {
+ while ($file = readdir($dir)) {
+ if (substr($file, -6) == '.cache' && ((filemtime($this->cache_dir . '/' . $file) + $cache_expire) < time()) ) {
+ unlink($this->cache_dir . '/' . $file);
+ }
+ }
+ }
+ } elseif ( $type == 'custom' ) {
+ $this->cache = "custom";
+ $this->custom_cache_get = $connection[0];
+ $this->custom_cache_set = $connection[1];
+ }
+ $this->cache_expire = $cache_expire;
+ }
+
+ function getCached ($request)
+ {
+ //Checks the database or filesystem for a cached result to the request.
+ //If there is no cache result, it returns a value of false. If it finds one,
+ //it returns the unparsed XML.
+ foreach ( $request as $key => $value ) {
+ if ( empty($value) ) unset($request[$key]);
+ else $request[$key] = (string) $request[$key];
+ }
+ //if ( is_user_logged_in() ) print_r($request);
+ $reqhash = md5(serialize($request));
+ $this->cache_key = $reqhash;
+ $this->cache_request = $request;
+ if ($this->cache == 'db') {
+ $result = mysql_query("SELECT response FROM " . $this->cache_table . " WHERE request = '" . $reqhash . "' AND DATE_SUB(NOW(), INTERVAL " . (int) $this->cache_expire . " SECOND) < expiration", $this->cache_db);
+ if ( mysql_num_rows($result) ) {
+ $result = mysql_fetch_assoc($result);
+ return $result['response'];
+ } else {
+ return false;
+ }
+ } elseif ($this->cache == 'fs') {
+ $file = $this->cache_dir . '/' . $reqhash . '.cache';
+ if (file_exists($file)) {
+ if ($this->php_version[0] > 4 || ($this->php_version[0] == 4 && $this->php_version[1] >= 3)) {
+ return file_get_contents($file);
+ } else {
+ return implode('', file($file));
+ }
+ }
+ } elseif ( $this->cache == 'custom' ) {
+ return call_user_func_array($this->custom_cache_get, array($reqhash));
+ }
+ return false;
+ }
+
+ function cache ($request, $response)
+ {
+ //Caches the unparsed response of a request.
+ unset($request['api_sig']);
+ foreach ( $request as $key => $value ) {
+ if ( empty($value) ) unset($request[$key]);
+ else $request[$key] = (string) $request[$key];
+ }
+ $reqhash = md5(serialize($request));
+ if ($this->cache == 'db') {
+ //$this->cache_db->query("DELETE FROM $this->cache_table WHERE request = '$reqhash'");
+ $result = mysql_query("SELECT COUNT(*) FROM " . $this->cache_table . " WHERE request = '" . $reqhash . "'", $this->cache_db);
+ $result = mysql_fetch_row($result);
+ if ( $result[0] ) {
+ $sql = "UPDATE " . $this->cache_table . " SET response = '" . str_replace("'", "''", $response) . "', expiration = '" . strftime("%Y-%m-%d %H:%M:%S") . "' WHERE request = '" . $reqhash . "'";
+ mysql_query($sql, $this->cache_db);
+ } else {
+ $sql = "INSERT INTO " . $this->cache_table . " (request, response, expiration) VALUES ('$reqhash', '" . str_replace("'", "''", $response) . "', '" . strftime("%Y-%m-%d %H:%M:%S") . "')";
+ mysql_query($sql, $this->cache_db);
+ }
+ } elseif ($this->cache == "fs") {
+ $file = $this->cache_dir . "/" . $reqhash . ".cache";
+ $fstream = fopen($file, "w");
+ $result = fwrite($fstream,$response);
+ fclose($fstream);
+ return $result;
+ } elseif ( $this->cache == "custom" ) {
+ return call_user_func_array($this->custom_cache_set, array($reqhash, $response, $this->cache_expire));
+ }
+ return false;
+ }
+
+ function setCustomPost ( $function ) {
+ $this->custom_post = $function;
+ }
+
+ function post ($data, $type = null) {
+ if ( is_null($type) ) {
+ $url = $this->rest_endpoint;
+ }
+
+ if ( !is_null($this->custom_post) ) {
+ return call_user_func($this->custom_post, $url, $data);
+ }
+
+ if ( !preg_match("|http://(.*?)(/.*)|", $url, $matches) ) {
+ die('There was some problem figuring out your endpoint');
+ }
+
+ if ( function_exists('curl_init') ) {
+ // Has curl. Use it!
+ $curl = curl_init($this->rest_endpoint);
+ curl_setopt($curl, CURLOPT_POST, true);
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ $response = curl_exec($curl);
+ curl_close($curl);
+ } else {
+ // Use sockets.
+ foreach ( $data as $key => $value ) {
+ $data[$key] = $key . '=' . urlencode($value);
+ }
+ $data = implode('&', $data);
+
+ $fp = @pfsockopen($matches[1], 80);
+ if (!$fp) {
+ die('Could not connect to the web service');
+ }
+ fputs ($fp,'POST ' . $matches[2] . " HTTP/1.1\n");
+ fputs ($fp,'Host: ' . $matches[1] . "\n");
+ fputs ($fp,"Content-type: application/x-www-form-urlencoded\n");
+ fputs ($fp,"Content-length: ".strlen($data)."\n");
+ fputs ($fp,"Connection: close\r\n\r\n");
+ fputs ($fp,$data . "\n\n");
+ $response = "";
+ while(!feof($fp)) {
+ $response .= fgets($fp, 1024);
+ }
+ fclose ($fp);
+ $chunked = false;
+ $http_status = trim(substr($response, 0, strpos($response, "\n")));
+ if ( $http_status != 'HTTP/1.1 200 OK' ) {
+ die('The web service endpoint returned a "' . $http_status . '" response');
+ }
+ if ( strpos($response, 'Transfer-Encoding: chunked') !== false ) {
+ $temp = trim(strstr($response, "\r\n\r\n"));
+ $response = '';
+ $length = trim(substr($temp, 0, strpos($temp, "\r")));
+ while ( trim($temp) != "0" && ($length = trim(substr($temp, 0, strpos($temp, "\r")))) != "0" ) {
+ $response .= trim(substr($temp, strlen($length)+2, hexdec($length)));
+ $temp = trim(substr($temp, strlen($length) + 2 + hexdec($length)));
+ }
+ } elseif ( strpos($response, 'HTTP/1.1 200 OK') !== false ) {
+ $response = trim(strstr($response, "\r\n\r\n"));
+ }
+ }
+ return $response;
+ }
+
+ function request ($command, $args = array(), $nocache = false)
+ {
+ //Sends a request to Flickr's REST endpoint via POST.
+ if (substr($command,0,7) != "flickr.") {
+ $command = "flickr." . $command;
+ }
+
+ //Process arguments, including method and login data.
+ $args = array_merge(array("method" => $command, "format" => "php_serial", "api_key" => $this->api_key), $args);
+ if (!empty($this->token)) {
+ $args = array_merge($args, array("auth_token" => $this->token));
+ } elseif (!empty($_SESSION['phpFlickr_auth_token'])) {
+ $args = array_merge($args, array("auth_token" => $_SESSION['phpFlickr_auth_token']));
+ }
+ ksort($args);
+ $auth_sig = "";
+ $this->last_request = $args;
+ if (!($this->response = $this->getCached($args)) || $nocache) {
+ foreach ($args as $key => $data) {
+ if ( is_null($data) ) {
+ unset($args[$key]);
+ continue;
+ }
+ $auth_sig .= $key . $data;
+ }
+ if (!empty($this->secret)) {
+ $api_sig = md5($this->secret . $auth_sig);
+ $args['api_sig'] = $api_sig;
+ }
+ $this->response = $this->post($args);
+ $this->cache($args, $this->response);
+ }
+
+ /*
+ * Uncomment this line (and comment out the next one) if you're doing large queries
+ * and you're concerned about time. This will, however, change the structure of
+ * the result, so be sure that you look at the results.
+ */
+ //$this->parsed_response = unserialize($this->response);
+ $this->parsed_response = $this->clean_text_nodes(unserialize($this->response));
+ if ($this->parsed_response['stat'] == 'fail') {
+ if ($this->die_on_error) die("The Flickr API returned the following error: #{$this->parsed_response['code']} - {$this->parsed_response['message']}");
+ else {
+ $this->error_code = $this->parsed_response['code'];
+ $this->error_msg = $this->parsed_response['message'];
+ $this->parsed_response = false;
+ }
+ } else {
+ $this->error_code = false;
+ $this->error_msg = false;
+ }
+ return $this->response;
+ }
+
+ function clean_text_nodes ($arr) {
+ if (!is_array($arr)) {
+ return $arr;
+ } elseif (count($arr) == 0) {
+ return $arr;
+ } elseif (count($arr) == 1 && array_key_exists('_content', $arr)) {
+ return $arr['_content'];
+ } else {
+ foreach ($arr as $key => $element) {
+ $arr[$key] = $this->clean_text_nodes($element);
+ }
+ return($arr);
+ }
+ }
+
+ function setToken ($token) {
+ // Sets an authentication token to use instead of the session variable
+ $this->token = $token;
+ }
+
+ function setProxy ($server, $port) {
+ // Sets the proxy for all phpFlickr calls.
+ $this->req->setProxy($server, $port);
+ }
+
+ function getErrorCode () {
+ // Returns the error code of the last call. If the last call did not
+ // return an error. This will return a false boolean.
+ return $this->error_code;
+ }
+
+ function getErrorMsg () {
+ // Returns the error message of the last call. If the last call did not
+ // return an error. This will return a false boolean.
+ return $this->error_msg;
+ }
+
+ /* These functions are front ends for the flickr calls */
+
+ function buildPhotoURL ($photo, $size = "Medium") {
+ //receives an array (can use the individual photo data returned
+ //from an API call) and returns a URL (doesn't mean that the
+ //file size exists)
+ $sizes = array(
+ "square" => "_s",
+ "large square" => "_q",
+ "thumbnail" => "_t",
+ "small" => "_m",
+ "medium" => "",
+ "medium_640" => "_z",
+ "large" => "_b",
+ "original" => "_o"
+ );
+
+ $size = strtolower($size);
+ if (!array_key_exists($size, $sizes)) {
+ $size = "medium";
+ }
+
+ if ($size == "original") {
+ $url = "http://farm" . $photo['farm'] . ".static.flickr.com/" . $photo['server'] . "/" . $photo['id'] . "_" . $photo['originalsecret'] . "_o" . "." . $photo['originalformat'];
+ } else {
+ $url = "http://farm" . $photo['farm'] . ".static.flickr.com/" . $photo['server'] . "/" . $photo['id'] . "_" . $photo['secret'] . $sizes[$size] . ".jpg";
+ }
+ return $url;
+ }
+
+ function getFriendlyGeodata ($lat, $lon) {
+ /* I've added this method to get the friendly geodata (i.e. 'in New York, NY') that the
+ * website provides, but isn't available in the API. I'm providing this service as long
+ * as it doesn't flood my server with requests and crash it all the time.
+ */
+ return unserialize(file_get_contents('http://phpflickr.com/geodata/?format=php&lat=' . $lat . '&lon=' . $lon));
+ }
+
+ function sync_upload ($photo, $title = null, $description = null, $tags = null, $is_public = null, $is_friend = null, $is_family = null) {
+ if ( function_exists('curl_init') ) {
+ // Has curl. Use it!
+
+ //Process arguments, including method and login data.
+ $args = array("api_key" => $this->api_key, "title" => $title, "description" => $description, "tags" => $tags, "is_public" => $is_public, "is_friend" => $is_friend, "is_family" => $is_family);
+ if (!empty($this->token)) {
+ $args = array_merge($args, array("auth_token" => $this->token));
+ } elseif (!empty($_SESSION['phpFlickr_auth_token'])) {
+ $args = array_merge($args, array("auth_token" => $_SESSION['phpFlickr_auth_token']));
+ }
+
+ ksort($args);
+ $auth_sig = "";
+ foreach ($args as $key => $data) {
+ if ( is_null($data) ) {
+ unset($args[$key]);
+ } else {
+ $auth_sig .= $key . $data;
+ }
+ }
+ if (!empty($this->secret)) {
+ $api_sig = md5($this->secret . $auth_sig);
+ $args["api_sig"] = $api_sig;
+ }
+
+ $photo = realpath($photo);
+ $args['photo'] = '@' . $photo;
+
+
+ $curl = curl_init($this->upload_endpoint);
+ curl_setopt($curl, CURLOPT_POST, true);
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $args);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ $response = curl_exec($curl);
+ $this->response = $response;
+ curl_close($curl);
+
+ $rsp = explode("\n", $response);
+ foreach ($rsp as $line) {
+ if (preg_match('|die_on_error)
+ die("The Flickr API returned the following error: #{$match[1]} - {$match[2]}");
+ else {
+ $this->error_code = $match[1];
+ $this->error_msg = $match[2];
+ $this->parsed_response = false;
+ return false;
+ }
+ } elseif (preg_match("|(.*)|", $line, $match)) {
+ $this->error_code = false;
+ $this->error_msg = false;
+ return $match[1];
+ }
+ }
+
+ } else {
+ die("Sorry, your server must support CURL in order to upload files");
+ }
+
+ }
+
+ function async_upload ($photo, $title = null, $description = null, $tags = null, $is_public = null, $is_friend = null, $is_family = null) {
+ if ( function_exists('curl_init') ) {
+ // Has curl. Use it!
+
+ //Process arguments, including method and login data.
+ $args = array("async" => 1, "api_key" => $this->api_key, "title" => $title, "description" => $description, "tags" => $tags, "is_public" => $is_public, "is_friend" => $is_friend, "is_family" => $is_family);
+ if (!empty($this->token)) {
+ $args = array_merge($args, array("auth_token" => $this->token));
+ } elseif (!empty($_SESSION['phpFlickr_auth_token'])) {
+ $args = array_merge($args, array("auth_token" => $_SESSION['phpFlickr_auth_token']));
+ }
+
+ ksort($args);
+ $auth_sig = "";
+ foreach ($args as $key => $data) {
+ if ( is_null($data) ) {
+ unset($args[$key]);
+ } else {
+ $auth_sig .= $key . $data;
+ }
+ }
+ if (!empty($this->secret)) {
+ $api_sig = md5($this->secret . $auth_sig);
+ $args["api_sig"] = $api_sig;
+ }
+
+ $photo = realpath($photo);
+ $args['photo'] = '@' . $photo;
+
+
+ $curl = curl_init($this->upload_endpoint);
+ curl_setopt($curl, CURLOPT_POST, true);
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $args);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ $response = curl_exec($curl);
+ $this->response = $response;
+ curl_close($curl);
+
+ $rsp = explode("\n", $response);
+ foreach ($rsp as $line) {
+ if (ereg('die_on_error)
+ die("The Flickr API returned the following error: #{$match[1]} - {$match[2]}");
+ else {
+ $this->error_code = $match[1];
+ $this->error_msg = $match[2];
+ $this->parsed_response = false;
+ return false;
+ }
+ } elseif (ereg("(.*)", $line, $match)) {
+ $this->error_code = false;
+ $this->error_msg = false;
+ return $match[1];
+ }
+ }
+ } else {
+ die("Sorry, your server must support CURL in order to upload files");
+ }
+ }
+
+ // Interface for new replace API method.
+ function replace ($photo, $photo_id, $async = null) {
+ if ( function_exists('curl_init') ) {
+ // Has curl. Use it!
+
+ //Process arguments, including method and login data.
+ $args = array("api_key" => $this->api_key, "photo_id" => $photo_id, "async" => $async);
+ if (!empty($this->token)) {
+ $args = array_merge($args, array("auth_token" => $this->token));
+ } elseif (!empty($_SESSION['phpFlickr_auth_token'])) {
+ $args = array_merge($args, array("auth_token" => $_SESSION['phpFlickr_auth_token']));
+ }
+
+ ksort($args);
+ $auth_sig = "";
+ foreach ($args as $key => $data) {
+ if ( is_null($data) ) {
+ unset($args[$key]);
+ } else {
+ $auth_sig .= $key . $data;
+ }
+ }
+ if (!empty($this->secret)) {
+ $api_sig = md5($this->secret . $auth_sig);
+ $args["api_sig"] = $api_sig;
+ }
+
+ $photo = realpath($photo);
+ $args['photo'] = '@' . $photo;
+
+
+ $curl = curl_init($this->replace_endpoint);
+ curl_setopt($curl, CURLOPT_POST, true);
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $args);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ $response = curl_exec($curl);
+ $this->response = $response;
+ curl_close($curl);
+
+ if ($async == 1)
+ $find = 'ticketid';
+ else
+ $find = 'photoid';
+
+ $rsp = explode("\n", $response);
+ foreach ($rsp as $line) {
+ if (preg_match('|die_on_error)
+ die("The Flickr API returned the following error: #{$match[1]} - {$match[2]}");
+ else {
+ $this->error_code = $match[1];
+ $this->error_msg = $match[2];
+ $this->parsed_response = false;
+ return false;
+ }
+ } elseif (preg_match("|<" . $find . ">(.*)|", $line, $match)) {
+ $this->error_code = false;
+ $this->error_msg = false;
+ return $match[1];
+ }
+ }
+ } else {
+ die("Sorry, your server must support CURL in order to upload files");
+ }
+ }
+
+ function auth ($perms = "read", $remember_uri = true) {
+ // Redirects to Flickr's authentication piece if there is no valid token.
+ // If remember_uri is set to false, the callback script (included) will
+ // redirect to its default page.
+
+ if (empty($_SESSION['phpFlickr_auth_token']) && empty($this->token)) {
+ if ( $remember_uri === true ) {
+ $_SESSION['phpFlickr_auth_redirect'] = $_SERVER['REQUEST_URI'];
+ } elseif ( $remember_uri !== false ) {
+ $_SESSION['phpFlickr_auth_redirect'] = $remember_uri;
+ }
+ $api_sig = md5($this->secret . "api_key" . $this->api_key . "perms" . $perms);
+
+ if ($this->service == "23") {
+ header("Location: http://www.23hq.com/services/auth/?api_key=" . $this->api_key . "&perms=" . $perms . "&api_sig=". $api_sig);
+ } else {
+ header("Location: http://www.flickr.com/services/auth/?api_key=" . $this->api_key . "&perms=" . $perms . "&api_sig=". $api_sig);
+ }
+ exit;
+ } else {
+ $tmp = $this->die_on_error;
+ $this->die_on_error = false;
+ $rsp = $this->auth_checkToken();
+ if ($this->error_code !== false) {
+ unset($_SESSION['phpFlickr_auth_token']);
+ $this->auth($perms, $remember_uri);
+ }
+ $this->die_on_error = $tmp;
+ return $rsp['perms'];
+ }
+ }
+
+ /*******************************
+
+ To use the phpFlickr::call method, pass a string containing the API method you want
+ to use and an associative array of arguments. For example:
+ $result = $f->call("flickr.photos.comments.getList", array("photo_id"=>'34952612'));
+ This method will allow you to make calls to arbitrary methods that haven't been
+ implemented in phpFlickr yet.
+
+ *******************************/
+
+ function call ($method, $arguments) {
+ foreach ( $arguments as $key => $value ) {
+ if ( is_null($value) ) unset($arguments[$key]);
+ }
+ $this->request($method, $arguments);
+ return $this->parsed_response ? $this->parsed_response : false;
+ }
+
+ /*
+ These functions are the direct implementations of flickr calls.
+ For method documentation, including arguments, visit the address
+ included in a comment in the function.
+ */
+
+ /* Activity methods */
+ function activity_userComments ($per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.activity.userComments.html */
+ $this->request('flickr.activity.userComments', array("per_page" => $per_page, "page" => $page));
+ return $this->parsed_response ? $this->parsed_response['items']['item'] : false;
+ }
+
+ function activity_userPhotos ($timeframe = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.activity.userPhotos.html */
+ $this->request('flickr.activity.userPhotos', array("timeframe" => $timeframe, "per_page" => $per_page, "page" => $page));
+ return $this->parsed_response ? $this->parsed_response['items']['item'] : false;
+ }
+
+ /* Authentication methods */
+ function auth_checkToken () {
+ /* http://www.flickr.com/services/api/flickr.auth.checkToken.html */
+ $this->request('flickr.auth.checkToken');
+ return $this->parsed_response ? $this->parsed_response['auth'] : false;
+ }
+
+ function auth_getFrob () {
+ /* http://www.flickr.com/services/api/flickr.auth.getFrob.html */
+ $this->request('flickr.auth.getFrob');
+ return $this->parsed_response ? $this->parsed_response['frob'] : false;
+ }
+
+ function auth_getFullToken ($mini_token) {
+ /* http://www.flickr.com/services/api/flickr.auth.getFullToken.html */
+ $this->request('flickr.auth.getFullToken', array('mini_token'=>$mini_token));
+ return $this->parsed_response ? $this->parsed_response['auth'] : false;
+ }
+
+ function auth_getToken ($frob) {
+ /* http://www.flickr.com/services/api/flickr.auth.getToken.html */
+ $this->request('flickr.auth.getToken', array('frob'=>$frob));
+ $_SESSION['phpFlickr_auth_token'] = $this->parsed_response['auth']['token'];
+ return $this->parsed_response ? $this->parsed_response['auth'] : false;
+ }
+
+ /* Blogs methods */
+ function blogs_getList ($service = NULL) {
+ /* http://www.flickr.com/services/api/flickr.blogs.getList.html */
+ $rsp = $this->call('flickr.blogs.getList', array('service' => $service));
+ return $rsp['blogs']['blog'];
+ }
+
+ function blogs_getServices () {
+ /* http://www.flickr.com/services/api/flickr.blogs.getServices.html */
+ return $this->call('flickr.blogs.getServices', array());
+ }
+
+ function blogs_postPhoto ($blog_id = NULL, $photo_id, $title, $description, $blog_password = NULL, $service = NULL) {
+ /* http://www.flickr.com/services/api/flickr.blogs.postPhoto.html */
+ return $this->call('flickr.blogs.postPhoto', array('blog_id' => $blog_id, 'photo_id' => $photo_id, 'title' => $title, 'description' => $description, 'blog_password' => $blog_password, 'service' => $service));
+ }
+
+ /* Collections Methods */
+ function collections_getInfo ($collection_id) {
+ /* http://www.flickr.com/services/api/flickr.collections.getInfo.html */
+ return $this->call('flickr.collections.getInfo', array('collection_id' => $collection_id));
+ }
+
+ function collections_getTree ($collection_id = NULL, $user_id = NULL) {
+ /* http://www.flickr.com/services/api/flickr.collections.getTree.html */
+ return $this->call('flickr.collections.getTree', array('collection_id' => $collection_id, 'user_id' => $user_id));
+ }
+
+ /* Commons Methods */
+ function commons_getInstitutions () {
+ /* http://www.flickr.com/services/api/flickr.commons.getInstitutions.html */
+ return $this->call('flickr.commons.getInstitutions', array());
+ }
+
+ /* Contacts Methods */
+ function contacts_getList ($filter = NULL, $page = NULL, $per_page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.contacts.getList.html */
+ $this->request('flickr.contacts.getList', array('filter'=>$filter, 'page'=>$page, 'per_page'=>$per_page));
+ return $this->parsed_response ? $this->parsed_response['contacts'] : false;
+ }
+
+ function contacts_getPublicList ($user_id, $page = NULL, $per_page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.contacts.getPublicList.html */
+ $this->request('flickr.contacts.getPublicList', array('user_id'=>$user_id, 'page'=>$page, 'per_page'=>$per_page));
+ return $this->parsed_response ? $this->parsed_response['contacts'] : false;
+ }
+
+ function contacts_getListRecentlyUploaded ($date_lastupload = NULL, $filter = NULL) {
+ /* http://www.flickr.com/services/api/flickr.contacts.getListRecentlyUploaded.html */
+ return $this->call('flickr.contacts.getListRecentlyUploaded', array('date_lastupload' => $date_lastupload, 'filter' => $filter));
+ }
+
+ /* Favorites Methods */
+ function favorites_add ($photo_id) {
+ /* http://www.flickr.com/services/api/flickr.favorites.add.html */
+ $this->request('flickr.favorites.add', array('photo_id'=>$photo_id), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function favorites_getList ($user_id = NULL, $jump_to = NULL, $min_fave_date = NULL, $max_fave_date = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.favorites.getList.html */
+ return $this->call('flickr.favorites.getList', array('user_id' => $user_id, 'jump_to' => $jump_to, 'min_fave_date' => $min_fave_date, 'max_fave_date' => $max_fave_date, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function favorites_getPublicList ($user_id, $jump_to = NULL, $min_fave_date = NULL, $max_fave_date = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.favorites.getPublicList.html */
+ return $this->call('flickr.favorites.getPublicList', array('user_id' => $user_id, 'jump_to' => $jump_to, 'min_fave_date' => $min_fave_date, 'max_fave_date' => $max_fave_date, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function favorites_remove ($photo_id, $user_id = NULL) {
+ /* http://www.flickr.com/services/api/flickr.favorites.remove.html */
+ $this->request("flickr.favorites.remove", array('photo_id' => $photo_id, 'user_id' => $user_id), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ /* Galleries Methods */
+ function galleries_addPhoto ($gallery_id, $photo_id, $comment = NULL) {
+ /* http://www.flickr.com/services/api/flickr.galleries.addPhoto.html */
+ return $this->call('flickr.galleries.addPhoto', array('gallery_id' => $gallery_id, 'photo_id' => $photo_id, 'comment' => $comment));
+ }
+
+ function galleries_create ($title, $description, $primary_photo_id = NULL) {
+ /* http://www.flickr.com/services/api/flickr.galleries.create.html */
+ return $this->call('flickr.galleries.create', array('title' => $title, 'description' => $description, 'primary_photo_id' => $primary_photo_id));
+ }
+
+ function galleries_editMeta ($gallery_id, $title, $description = NULL) {
+ /* http://www.flickr.com/services/api/flickr.galleries.editMeta.html */
+ return $this->call('flickr.galleries.editMeta', array('gallery_id' => $gallery_id, 'title' => $title, 'description' => $description));
+ }
+
+ function galleries_editPhoto ($gallery_id, $photo_id, $comment) {
+ /* http://www.flickr.com/services/api/flickr.galleries.editPhoto.html */
+ return $this->call('flickr.galleries.editPhoto', array('gallery_id' => $gallery_id, 'photo_id' => $photo_id, 'comment' => $comment));
+ }
+
+ function galleries_editPhotos ($gallery_id, $primary_photo_id, $photo_ids) {
+ /* http://www.flickr.com/services/api/flickr.galleries.editPhotos.html */
+ return $this->call('flickr.galleries.editPhotos', array('gallery_id' => $gallery_id, 'primary_photo_id' => $primary_photo_id, 'photo_ids' => $photo_ids));
+ }
+
+ function galleries_getInfo ($gallery_id) {
+ /* http://www.flickr.com/services/api/flickr.galleries.getInfo.html */
+ return $this->call('flickr.galleries.getInfo', array('gallery_id' => $gallery_id));
+ }
+
+ function galleries_getList ($user_id, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.galleries.getList.html */
+ return $this->call('flickr.galleries.getList', array('user_id' => $user_id, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function galleries_getListForPhoto ($photo_id, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.galleries.getListForPhoto.html */
+ return $this->call('flickr.galleries.getListForPhoto', array('photo_id' => $photo_id, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function galleries_getPhotos ($gallery_id, $extras = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.galleries.getPhotos.html */
+ return $this->call('flickr.galleries.getPhotos', array('gallery_id' => $gallery_id, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ /* Groups Methods */
+ function groups_browse ($cat_id = NULL) {
+ /* http://www.flickr.com/services/api/flickr.groups.browse.html */
+ $this->request("flickr.groups.browse", array("cat_id"=>$cat_id));
+ return $this->parsed_response ? $this->parsed_response['category'] : false;
+ }
+
+ function groups_getInfo ($group_id, $lang = NULL) {
+ /* http://www.flickr.com/services/api/flickr.groups.getInfo.html */
+ return $this->call('flickr.groups.getInfo', array('group_id' => $group_id, 'lang' => $lang));
+ }
+
+ function groups_search ($text, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.groups.search.html */
+ $this->request("flickr.groups.search", array("text"=>$text,"per_page"=>$per_page,"page"=>$page));
+ return $this->parsed_response ? $this->parsed_response['groups'] : false;
+ }
+
+ /* Groups Members Methods */
+ function groups_members_getList ($group_id, $membertypes = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.groups.members.getList.html */
+ return $this->call('flickr.groups.members.getList', array('group_id' => $group_id, 'membertypes' => $membertypes, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ /* Groups Pools Methods */
+ function groups_pools_add ($photo_id, $group_id) {
+ /* http://www.flickr.com/services/api/flickr.groups.pools.add.html */
+ $this->request("flickr.groups.pools.add", array("photo_id"=>$photo_id, "group_id"=>$group_id), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function groups_pools_getContext ($photo_id, $group_id, $num_prev = NULL, $num_next = NULL) {
+ /* http://www.flickr.com/services/api/flickr.groups.pools.getContext.html */
+ return $this->call('flickr.groups.pools.getContext', array('photo_id' => $photo_id, 'group_id' => $group_id, 'num_prev' => $num_prev, 'num_next' => $num_next));
+ }
+
+ function groups_pools_getGroups ($page = NULL, $per_page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.groups.pools.getGroups.html */
+ $this->request("flickr.groups.pools.getGroups", array('page'=>$page, 'per_page'=>$per_page));
+ return $this->parsed_response ? $this->parsed_response['groups'] : false;
+ }
+
+ function groups_pools_getPhotos ($group_id, $tags = NULL, $user_id = NULL, $jump_to = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.groups.pools.getPhotos.html */
+ if (is_array($extras)) {
+ $extras = implode(",", $extras);
+ }
+ return $this->call('flickr.groups.pools.getPhotos', array('group_id' => $group_id, 'tags' => $tags, 'user_id' => $user_id, 'jump_to' => $jump_to, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function groups_pools_remove ($photo_id, $group_id) {
+ /* http://www.flickr.com/services/api/flickr.groups.pools.remove.html */
+ $this->request("flickr.groups.pools.remove", array("photo_id"=>$photo_id, "group_id"=>$group_id), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ /* Interestingness methods */
+ function interestingness_getList ($date = NULL, $use_panda = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.interestingness.getList.html */
+ if (is_array($extras)) {
+ $extras = implode(",", $extras);
+ }
+
+ return $this->call('flickr.interestingness.getList', array('date' => $date, 'use_panda' => $use_panda, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ /* Machine Tag methods */
+ function machinetags_getNamespaces ($predicate = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.machinetags.getNamespaces.html */
+ return $this->call('flickr.machinetags.getNamespaces', array('predicate' => $predicate, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function machinetags_getPairs ($namespace = NULL, $predicate = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.machinetags.getPairs.html */
+ return $this->call('flickr.machinetags.getPairs', array('namespace' => $namespace, 'predicate' => $predicate, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function machinetags_getPredicates ($namespace = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.machinetags.getPredicates.html */
+ return $this->call('flickr.machinetags.getPredicates', array('namespace' => $namespace, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function machinetags_getRecentValues ($namespace = NULL, $predicate = NULL, $added_since = NULL) {
+ /* http://www.flickr.com/services/api/flickr.machinetags.getRecentValues.html */
+ return $this->call('flickr.machinetags.getRecentValues', array('namespace' => $namespace, 'predicate' => $predicate, 'added_since' => $added_since));
+ }
+
+ function machinetags_getValues ($namespace, $predicate, $per_page = NULL, $page = NULL, $usage = NULL) {
+ /* http://www.flickr.com/services/api/flickr.machinetags.getValues.html */
+ return $this->call('flickr.machinetags.getValues', array('namespace' => $namespace, 'predicate' => $predicate, 'per_page' => $per_page, 'page' => $page, 'usage' => $usage));
+ }
+
+ /* Panda methods */
+ function panda_getList () {
+ /* http://www.flickr.com/services/api/flickr.panda.getList.html */
+ return $this->call('flickr.panda.getList', array());
+ }
+
+ function panda_getPhotos ($panda_name, $extras = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.panda.getPhotos.html */
+ return $this->call('flickr.panda.getPhotos', array('panda_name' => $panda_name, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ /* People methods */
+ function people_findByEmail ($find_email) {
+ /* http://www.flickr.com/services/api/flickr.people.findByEmail.html */
+ $this->request("flickr.people.findByEmail", array("find_email"=>$find_email));
+ return $this->parsed_response ? $this->parsed_response['user'] : false;
+ }
+
+ function people_findByUsername ($username) {
+ /* http://www.flickr.com/services/api/flickr.people.findByUsername.html */
+ $this->request("flickr.people.findByUsername", array("username"=>$username));
+ return $this->parsed_response ? $this->parsed_response['user'] : false;
+ }
+
+ function people_getInfo ($user_id) {
+ /* http://www.flickr.com/services/api/flickr.people.getInfo.html */
+ $this->request("flickr.people.getInfo", array("user_id"=>$user_id));
+ return $this->parsed_response ? $this->parsed_response['person'] : false;
+ }
+
+ function people_getPhotos ($user_id, $args = array()) {
+ /* This function strays from the method of arguments that I've
+ * used in the other functions for the fact that there are just
+ * so many arguments to this API method. What you'll need to do
+ * is pass an associative array to the function containing the
+ * arguments you want to pass to the API. For example:
+ * $photos = $f->photos_search(array("tags"=>"brown,cow", "tag_mode"=>"any"));
+ * This will return photos tagged with either "brown" or "cow"
+ * or both. See the API documentation (link below) for a full
+ * list of arguments.
+ */
+
+ /* http://www.flickr.com/services/api/flickr.people.getPhotos.html */
+ return $this->call('flickr.people.getPhotos', array_merge(array('user_id' => $user_id), $args));
+ }
+
+ function people_getPhotosOf ($user_id, $extras = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.people.getPhotosOf.html */
+ return $this->call('flickr.people.getPhotosOf', array('user_id' => $user_id, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function people_getPublicGroups ($user_id) {
+ /* http://www.flickr.com/services/api/flickr.people.getPublicGroups.html */
+ $this->request("flickr.people.getPublicGroups", array("user_id"=>$user_id));
+ return $this->parsed_response ? $this->parsed_response['groups']['group'] : false;
+ }
+
+ function people_getPublicPhotos ($user_id, $safe_search = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.people.getPublicPhotos.html */
+ return $this->call('flickr.people.getPublicPhotos', array('user_id' => $user_id, 'safe_search' => $safe_search, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function people_getUploadStatus () {
+ /* http://www.flickr.com/services/api/flickr.people.getUploadStatus.html */
+ /* Requires Authentication */
+ $this->request("flickr.people.getUploadStatus");
+ return $this->parsed_response ? $this->parsed_response['user'] : false;
+ }
+
+
+ /* Photos Methods */
+ function photos_addTags ($photo_id, $tags) {
+ /* http://www.flickr.com/services/api/flickr.photos.addTags.html */
+ $this->request("flickr.photos.addTags", array("photo_id"=>$photo_id, "tags"=>$tags), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photos_delete ($photo_id) {
+ /* http://www.flickr.com/services/api/flickr.photos.delete.html */
+ $this->request("flickr.photos.delete", array("photo_id"=>$photo_id), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photos_getAllContexts ($photo_id) {
+ /* http://www.flickr.com/services/api/flickr.photos.getAllContexts.html */
+ $this->request("flickr.photos.getAllContexts", array("photo_id"=>$photo_id));
+ return $this->parsed_response ? $this->parsed_response : false;
+ }
+
+ function photos_getContactsPhotos ($count = NULL, $just_friends = NULL, $single_photo = NULL, $include_self = NULL, $extras = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.getContactsPhotos.html */
+ $this->request("flickr.photos.getContactsPhotos", array("count"=>$count, "just_friends"=>$just_friends, "single_photo"=>$single_photo, "include_self"=>$include_self, "extras"=>$extras));
+ return $this->parsed_response ? $this->parsed_response['photos']['photo'] : false;
+ }
+
+ function photos_getContactsPublicPhotos ($user_id, $count = NULL, $just_friends = NULL, $single_photo = NULL, $include_self = NULL, $extras = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.getContactsPublicPhotos.html */
+ $this->request("flickr.photos.getContactsPublicPhotos", array("user_id"=>$user_id, "count"=>$count, "just_friends"=>$just_friends, "single_photo"=>$single_photo, "include_self"=>$include_self, "extras"=>$extras));
+ return $this->parsed_response ? $this->parsed_response['photos']['photo'] : false;
+ }
+
+ function photos_getContext ($photo_id, $num_prev = NULL, $num_next = NULL, $extras = NULL, $order_by = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.getContext.html */
+ return $this->call('flickr.photos.getContext', array('photo_id' => $photo_id, 'num_prev' => $num_prev, 'num_next' => $num_next, 'extras' => $extras, 'order_by' => $order_by));
+ }
+
+ function photos_getCounts ($dates = NULL, $taken_dates = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.getCounts.html */
+ $this->request("flickr.photos.getCounts", array("dates"=>$dates, "taken_dates"=>$taken_dates));
+ return $this->parsed_response ? $this->parsed_response['photocounts']['photocount'] : false;
+ }
+
+ function photos_getExif ($photo_id, $secret = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.getExif.html */
+ $this->request("flickr.photos.getExif", array("photo_id"=>$photo_id, "secret"=>$secret));
+ return $this->parsed_response ? $this->parsed_response['photo'] : false;
+ }
+
+ function photos_getFavorites ($photo_id, $page = NULL, $per_page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.getFavorites.html */
+ $this->request("flickr.photos.getFavorites", array("photo_id"=>$photo_id, "page"=>$page, "per_page"=>$per_page));
+ return $this->parsed_response ? $this->parsed_response['photo'] : false;
+ }
+
+ function photos_getInfo ($photo_id, $secret = NULL, $humandates = NULL, $privacy_filter = NULL, $get_contexts = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.getInfo.html */
+ return $this->call('flickr.photos.getInfo', array('photo_id' => $photo_id, 'secret' => $secret, 'humandates' => $humandates, 'privacy_filter' => $privacy_filter, 'get_contexts' => $get_contexts));
+ }
+
+ function photos_getNotInSet ($max_upload_date = NULL, $min_taken_date = NULL, $max_taken_date = NULL, $privacy_filter = NULL, $media = NULL, $min_upload_date = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.getNotInSet.html */
+ return $this->call('flickr.photos.getNotInSet', array('max_upload_date' => $max_upload_date, 'min_taken_date' => $min_taken_date, 'max_taken_date' => $max_taken_date, 'privacy_filter' => $privacy_filter, 'media' => $media, 'min_upload_date' => $min_upload_date, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function photos_getPerms ($photo_id) {
+ /* http://www.flickr.com/services/api/flickr.photos.getPerms.html */
+ $this->request("flickr.photos.getPerms", array("photo_id"=>$photo_id));
+ return $this->parsed_response ? $this->parsed_response['perms'] : false;
+ }
+
+ function photos_getRecent ($jump_to = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.getRecent.html */
+ if (is_array($extras)) {
+ $extras = implode(",", $extras);
+ }
+ return $this->call('flickr.photos.getRecent', array('jump_to' => $jump_to, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function photos_getSizes ($photo_id) {
+ /* http://www.flickr.com/services/api/flickr.photos.getSizes.html */
+ $this->request("flickr.photos.getSizes", array("photo_id"=>$photo_id));
+ return $this->parsed_response ? $this->parsed_response['sizes']['size'] : false;
+ }
+
+ function photos_getUntagged ($min_upload_date = NULL, $max_upload_date = NULL, $min_taken_date = NULL, $max_taken_date = NULL, $privacy_filter = NULL, $media = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.getUntagged.html */
+ return $this->call('flickr.photos.getUntagged', array('min_upload_date' => $min_upload_date, 'max_upload_date' => $max_upload_date, 'min_taken_date' => $min_taken_date, 'max_taken_date' => $max_taken_date, 'privacy_filter' => $privacy_filter, 'media' => $media, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function photos_getWithGeoData ($args = array()) {
+ /* See the documentation included with the photos_search() function.
+ * I'm using the same style of arguments for this function. The only
+ * difference here is that this doesn't require any arguments. The
+ * flickr.photos.search method requires at least one search parameter.
+ */
+ /* http://www.flickr.com/services/api/flickr.photos.getWithGeoData.html */
+ $this->request("flickr.photos.getWithGeoData", $args);
+ return $this->parsed_response ? $this->parsed_response['photos'] : false;
+ }
+
+ function photos_getWithoutGeoData ($args = array()) {
+ /* See the documentation included with the photos_search() function.
+ * I'm using the same style of arguments for this function. The only
+ * difference here is that this doesn't require any arguments. The
+ * flickr.photos.search method requires at least one search parameter.
+ */
+ /* http://www.flickr.com/services/api/flickr.photos.getWithoutGeoData.html */
+ $this->request("flickr.photos.getWithoutGeoData", $args);
+ return $this->parsed_response ? $this->parsed_response['photos'] : false;
+ }
+
+ function photos_recentlyUpdated ($min_date, $extras = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.recentlyUpdated.html */
+ return $this->call('flickr.photos.recentlyUpdated', array('min_date' => $min_date, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function photos_removeTag ($tag_id) {
+ /* http://www.flickr.com/services/api/flickr.photos.removeTag.html */
+ $this->request("flickr.photos.removeTag", array("tag_id"=>$tag_id), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photos_search ($args = array()) {
+ /* This function strays from the method of arguments that I've
+ * used in the other functions for the fact that there are just
+ * so many arguments to this API method. What you'll need to do
+ * is pass an associative array to the function containing the
+ * arguments you want to pass to the API. For example:
+ * $photos = $f->photos_search(array("tags"=>"brown,cow", "tag_mode"=>"any"));
+ * This will return photos tagged with either "brown" or "cow"
+ * or both. See the API documentation (link below) for a full
+ * list of arguments.
+ */
+
+ /* http://www.flickr.com/services/api/flickr.photos.search.html */
+ $this->request("flickr.photos.search", $args);
+ return $this->parsed_response ? $this->parsed_response['photos'] : false;
+ }
+
+ function photos_setContentType ($photo_id, $content_type) {
+ /* http://www.flickr.com/services/api/flickr.photos.setContentType.html */
+ return $this->call('flickr.photos.setContentType', array('photo_id' => $photo_id, 'content_type' => $content_type));
+ }
+
+ function photos_setDates ($photo_id, $date_posted = NULL, $date_taken = NULL, $date_taken_granularity = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.setDates.html */
+ $this->request("flickr.photos.setDates", array("photo_id"=>$photo_id, "date_posted"=>$date_posted, "date_taken"=>$date_taken, "date_taken_granularity"=>$date_taken_granularity), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photos_setMeta ($photo_id, $title, $description) {
+ /* http://www.flickr.com/services/api/flickr.photos.setMeta.html */
+ $this->request("flickr.photos.setMeta", array("photo_id"=>$photo_id, "title"=>$title, "description"=>$description), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photos_setPerms ($photo_id, $is_public, $is_friend, $is_family, $perm_comment, $perm_addmeta) {
+ /* http://www.flickr.com/services/api/flickr.photos.setPerms.html */
+ $this->request("flickr.photos.setPerms", array("photo_id"=>$photo_id, "is_public"=>$is_public, "is_friend"=>$is_friend, "is_family"=>$is_family, "perm_comment"=>$perm_comment, "perm_addmeta"=>$perm_addmeta), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photos_setSafetyLevel ($photo_id, $safety_level = NULL, $hidden = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.setSafetyLevel.html */
+ return $this->call('flickr.photos.setSafetyLevel', array('photo_id' => $photo_id, 'safety_level' => $safety_level, 'hidden' => $hidden));
+ }
+
+ function photos_setTags ($photo_id, $tags) {
+ /* http://www.flickr.com/services/api/flickr.photos.setTags.html */
+ $this->request("flickr.photos.setTags", array("photo_id"=>$photo_id, "tags"=>$tags), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ /* Photos - Comments Methods */
+ function photos_comments_addComment ($photo_id, $comment_text) {
+ /* http://www.flickr.com/services/api/flickr.photos.comments.addComment.html */
+ $this->request("flickr.photos.comments.addComment", array("photo_id" => $photo_id, "comment_text"=>$comment_text), TRUE);
+ return $this->parsed_response ? $this->parsed_response['comment'] : false;
+ }
+
+ function photos_comments_deleteComment ($comment_id) {
+ /* http://www.flickr.com/services/api/flickr.photos.comments.deleteComment.html */
+ $this->request("flickr.photos.comments.deleteComment", array("comment_id" => $comment_id), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photos_comments_editComment ($comment_id, $comment_text) {
+ /* http://www.flickr.com/services/api/flickr.photos.comments.editComment.html */
+ $this->request("flickr.photos.comments.editComment", array("comment_id" => $comment_id, "comment_text"=>$comment_text), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photos_comments_getList ($photo_id, $min_comment_date = NULL, $max_comment_date = NULL, $page = NULL, $per_page = NULL, $include_faves = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.comments.getList.html */
+ return $this->call('flickr.photos.comments.getList', array('photo_id' => $photo_id, 'min_comment_date' => $min_comment_date, 'max_comment_date' => $max_comment_date, 'page' => $page, 'per_page' => $per_page, 'include_faves' => $include_faves));
+ }
+
+ function photos_comments_getRecentForContacts ($date_lastcomment = NULL, $contacts_filter = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.comments.getRecentForContacts.html */
+ return $this->call('flickr.photos.comments.getRecentForContacts', array('date_lastcomment' => $date_lastcomment, 'contacts_filter' => $contacts_filter, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ /* Photos - Geo Methods */
+ function photos_geo_batchCorrectLocation ($lat, $lon, $accuracy, $place_id = NULL, $woe_id = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.geo.batchCorrectLocation.html */
+ return $this->call('flickr.photos.geo.batchCorrectLocation', array('lat' => $lat, 'lon' => $lon, 'accuracy' => $accuracy, 'place_id' => $place_id, 'woe_id' => $woe_id));
+ }
+
+ function photos_geo_correctLocation ($photo_id, $place_id = NULL, $woe_id = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.geo.correctLocation.html */
+ return $this->call('flickr.photos.geo.correctLocation', array('photo_id' => $photo_id, 'place_id' => $place_id, 'woe_id' => $woe_id));
+ }
+
+ function photos_geo_getLocation ($photo_id) {
+ /* http://www.flickr.com/services/api/flickr.photos.geo.getLocation.html */
+ $this->request("flickr.photos.geo.getLocation", array("photo_id"=>$photo_id));
+ return $this->parsed_response ? $this->parsed_response['photo'] : false;
+ }
+
+ function photos_geo_getPerms ($photo_id) {
+ /* http://www.flickr.com/services/api/flickr.photos.geo.getPerms.html */
+ $this->request("flickr.photos.geo.getPerms", array("photo_id"=>$photo_id));
+ return $this->parsed_response ? $this->parsed_response['perms'] : false;
+ }
+
+ function photos_geo_photosForLocation ($lat, $lon, $accuracy = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.geo.photosForLocation.html */
+ return $this->call('flickr.photos.geo.photosForLocation', array('lat' => $lat, 'lon' => $lon, 'accuracy' => $accuracy, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function photos_geo_removeLocation ($photo_id) {
+ /* http://www.flickr.com/services/api/flickr.photos.geo.removeLocation.html */
+ $this->request("flickr.photos.geo.removeLocation", array("photo_id"=>$photo_id), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photos_geo_setContext ($photo_id, $context) {
+ /* http://www.flickr.com/services/api/flickr.photos.geo.setContext.html */
+ return $this->call('flickr.photos.geo.setContext', array('photo_id' => $photo_id, 'context' => $context));
+ }
+
+ function photos_geo_setLocation ($photo_id, $lat, $lon, $accuracy = NULL, $context = NULL, $bookmark_id = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.geo.setLocation.html */
+ return $this->call('flickr.photos.geo.setLocation', array('photo_id' => $photo_id, 'lat' => $lat, 'lon' => $lon, 'accuracy' => $accuracy, 'context' => $context, 'bookmark_id' => $bookmark_id));
+ }
+
+ function photos_geo_setPerms ($is_public, $is_contact, $is_friend, $is_family, $photo_id) {
+ /* http://www.flickr.com/services/api/flickr.photos.geo.setPerms.html */
+ return $this->call('flickr.photos.geo.setPerms', array('is_public' => $is_public, 'is_contact' => $is_contact, 'is_friend' => $is_friend, 'is_family' => $is_family, 'photo_id' => $photo_id));
+ }
+
+ /* Photos - Licenses Methods */
+ function photos_licenses_getInfo () {
+ /* http://www.flickr.com/services/api/flickr.photos.licenses.getInfo.html */
+ $this->request("flickr.photos.licenses.getInfo");
+ return $this->parsed_response ? $this->parsed_response['licenses']['license'] : false;
+ }
+
+ function photos_licenses_setLicense ($photo_id, $license_id) {
+ /* http://www.flickr.com/services/api/flickr.photos.licenses.setLicense.html */
+ /* Requires Authentication */
+ $this->request("flickr.photos.licenses.setLicense", array("photo_id"=>$photo_id, "license_id"=>$license_id), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ /* Photos - Notes Methods */
+ function photos_notes_add ($photo_id, $note_x, $note_y, $note_w, $note_h, $note_text) {
+ /* http://www.flickr.com/services/api/flickr.photos.notes.add.html */
+ $this->request("flickr.photos.notes.add", array("photo_id" => $photo_id, "note_x" => $note_x, "note_y" => $note_y, "note_w" => $note_w, "note_h" => $note_h, "note_text" => $note_text), TRUE);
+ return $this->parsed_response ? $this->parsed_response['note'] : false;
+ }
+
+ function photos_notes_delete ($note_id) {
+ /* http://www.flickr.com/services/api/flickr.photos.notes.delete.html */
+ $this->request("flickr.photos.notes.delete", array("note_id" => $note_id), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photos_notes_edit ($note_id, $note_x, $note_y, $note_w, $note_h, $note_text) {
+ /* http://www.flickr.com/services/api/flickr.photos.notes.edit.html */
+ $this->request("flickr.photos.notes.edit", array("note_id" => $note_id, "note_x" => $note_x, "note_y" => $note_y, "note_w" => $note_w, "note_h" => $note_h, "note_text" => $note_text), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ /* Photos - Transform Methods */
+ function photos_transform_rotate ($photo_id, $degrees) {
+ /* http://www.flickr.com/services/api/flickr.photos.transform.rotate.html */
+ $this->request("flickr.photos.transform.rotate", array("photo_id" => $photo_id, "degrees" => $degrees), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ /* Photos - People Methods */
+ function photos_people_add ($photo_id, $user_id, $person_x = NULL, $person_y = NULL, $person_w = NULL, $person_h = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.people.add.html */
+ return $this->call('flickr.photos.people.add', array('photo_id' => $photo_id, 'user_id' => $user_id, 'person_x' => $person_x, 'person_y' => $person_y, 'person_w' => $person_w, 'person_h' => $person_h));
+ }
+
+ function photos_people_delete ($photo_id, $user_id, $email = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.people.delete.html */
+ return $this->call('flickr.photos.people.delete', array('photo_id' => $photo_id, 'user_id' => $user_id, 'email' => $email));
+ }
+
+ function photos_people_deleteCoords ($photo_id, $user_id) {
+ /* http://www.flickr.com/services/api/flickr.photos.people.deleteCoords.html */
+ return $this->call('flickr.photos.people.deleteCoords', array('photo_id' => $photo_id, 'user_id' => $user_id));
+ }
+
+ function photos_people_editCoords ($photo_id, $user_id, $person_x, $person_y, $person_w, $person_h, $email = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photos.people.editCoords.html */
+ return $this->call('flickr.photos.people.editCoords', array('photo_id' => $photo_id, 'user_id' => $user_id, 'person_x' => $person_x, 'person_y' => $person_y, 'person_w' => $person_w, 'person_h' => $person_h, 'email' => $email));
+ }
+
+ function photos_people_getList ($photo_id) {
+ /* http://www.flickr.com/services/api/flickr.photos.people.getList.html */
+ return $this->call('flickr.photos.people.getList', array('photo_id' => $photo_id));
+ }
+
+ /* Photos - Upload Methods */
+ function photos_upload_checkTickets ($tickets) {
+ /* http://www.flickr.com/services/api/flickr.photos.upload.checkTickets.html */
+ if (is_array($tickets)) {
+ $tickets = implode(",", $tickets);
+ }
+ $this->request("flickr.photos.upload.checkTickets", array("tickets" => $tickets), TRUE);
+ return $this->parsed_response ? $this->parsed_response['uploader']['ticket'] : false;
+ }
+
+ /* Photosets Methods */
+ function photosets_addPhoto ($photoset_id, $photo_id) {
+ /* http://www.flickr.com/services/api/flickr.photosets.addPhoto.html */
+ $this->request("flickr.photosets.addPhoto", array("photoset_id" => $photoset_id, "photo_id" => $photo_id), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photosets_create ($title, $description, $primary_photo_id) {
+ /* http://www.flickr.com/services/api/flickr.photosets.create.html */
+ $this->request("flickr.photosets.create", array("title" => $title, "primary_photo_id" => $primary_photo_id, "description" => $description), TRUE);
+ return $this->parsed_response ? $this->parsed_response['photoset'] : false;
+ }
+
+ function photosets_delete ($photoset_id) {
+ /* http://www.flickr.com/services/api/flickr.photosets.delete.html */
+ $this->request("flickr.photosets.delete", array("photoset_id" => $photoset_id), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photosets_editMeta ($photoset_id, $title, $description = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photosets.editMeta.html */
+ $this->request("flickr.photosets.editMeta", array("photoset_id" => $photoset_id, "title" => $title, "description" => $description), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photosets_editPhotos ($photoset_id, $primary_photo_id, $photo_ids) {
+ /* http://www.flickr.com/services/api/flickr.photosets.editPhotos.html */
+ $this->request("flickr.photosets.editPhotos", array("photoset_id" => $photoset_id, "primary_photo_id" => $primary_photo_id, "photo_ids" => $photo_ids), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photosets_getContext ($photo_id, $photoset_id, $num_prev = NULL, $num_next = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photosets.getContext.html */
+ return $this->call('flickr.photosets.getContext', array('photo_id' => $photo_id, 'photoset_id' => $photoset_id, 'num_prev' => $num_prev, 'num_next' => $num_next));
+ }
+
+ function photosets_getInfo ($photoset_id) {
+ /* http://www.flickr.com/services/api/flickr.photosets.getInfo.html */
+ $this->request("flickr.photosets.getInfo", array("photoset_id" => $photoset_id));
+ return $this->parsed_response ? $this->parsed_response['photoset'] : false;
+ }
+
+ function photosets_getList ($user_id = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photosets.getList.html */
+ $this->request("flickr.photosets.getList", array("user_id" => $user_id));
+ return $this->parsed_response ? $this->parsed_response['photosets'] : false;
+ }
+
+ function photosets_getPhotos ($photoset_id, $extras = NULL, $privacy_filter = NULL, $per_page = NULL, $page = NULL, $media = NULL) {
+ /* http://www.flickr.com/services/api/flickr.photosets.getPhotos.html */
+ return $this->call('flickr.photosets.getPhotos', array('photoset_id' => $photoset_id, 'extras' => $extras, 'privacy_filter' => $privacy_filter, 'per_page' => $per_page, 'page' => $page, 'media' => $media));
+ }
+
+ function photosets_orderSets ($photoset_ids) {
+ /* http://www.flickr.com/services/api/flickr.photosets.orderSets.html */
+ if (is_array($photoset_ids)) {
+ $photoset_ids = implode(",", $photoset_ids);
+ }
+ $this->request("flickr.photosets.orderSets", array("photoset_ids" => $photoset_ids), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photosets_removePhoto ($photoset_id, $photo_id) {
+ /* http://www.flickr.com/services/api/flickr.photosets.removePhoto.html */
+ $this->request("flickr.photosets.removePhoto", array("photoset_id" => $photoset_id, "photo_id" => $photo_id), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photosets_removePhotos ($photoset_id, $photo_ids) {
+ /* http://www.flickr.com/services/api/flickr.photosets.removePhotos.html */
+ return $this->call('flickr.photosets.removePhotos', array('photoset_id' => $photoset_id, 'photo_ids' => $photo_ids));
+ }
+
+ function photosets_reorderPhotos ($photoset_id, $photo_ids) {
+ /* http://www.flickr.com/services/api/flickr.photosets.reorderPhotos.html */
+ return $this->call('flickr.photosets.reorderPhotos', array('photoset_id' => $photoset_id, 'photo_ids' => $photo_ids));
+ }
+
+ function photosets_setPrimaryPhoto ($photoset_id, $photo_id) {
+ /* http://www.flickr.com/services/api/flickr.photosets.setPrimaryPhoto.html */
+ return $this->call('flickr.photosets.setPrimaryPhoto', array('photoset_id' => $photoset_id, 'photo_id' => $photo_id));
+ }
+
+ /* Photosets Comments Methods */
+ function photosets_comments_addComment ($photoset_id, $comment_text) {
+ /* http://www.flickr.com/services/api/flickr.photosets.comments.addComment.html */
+ $this->request("flickr.photosets.comments.addComment", array("photoset_id" => $photoset_id, "comment_text"=>$comment_text), TRUE);
+ return $this->parsed_response ? $this->parsed_response['comment'] : false;
+ }
+
+ function photosets_comments_deleteComment ($comment_id) {
+ /* http://www.flickr.com/services/api/flickr.photosets.comments.deleteComment.html */
+ $this->request("flickr.photosets.comments.deleteComment", array("comment_id" => $comment_id), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photosets_comments_editComment ($comment_id, $comment_text) {
+ /* http://www.flickr.com/services/api/flickr.photosets.comments.editComment.html */
+ $this->request("flickr.photosets.comments.editComment", array("comment_id" => $comment_id, "comment_text"=>$comment_text), TRUE);
+ return $this->parsed_response ? true : false;
+ }
+
+ function photosets_comments_getList ($photoset_id) {
+ /* http://www.flickr.com/services/api/flickr.photosets.comments.getList.html */
+ $this->request("flickr.photosets.comments.getList", array("photoset_id"=>$photoset_id));
+ return $this->parsed_response ? $this->parsed_response['comments'] : false;
+ }
+
+ /* Places Methods */
+ function places_find ($query) {
+ /* http://www.flickr.com/services/api/flickr.places.find.html */
+ return $this->call('flickr.places.find', array('query' => $query));
+ }
+
+ function places_findByLatLon ($lat, $lon, $accuracy = NULL) {
+ /* http://www.flickr.com/services/api/flickr.places.findByLatLon.html */
+ return $this->call('flickr.places.findByLatLon', array('lat' => $lat, 'lon' => $lon, 'accuracy' => $accuracy));
+ }
+
+ function places_getChildrenWithPhotosPublic ($place_id = NULL, $woe_id = NULL) {
+ /* http://www.flickr.com/services/api/flickr.places.getChildrenWithPhotosPublic.html */
+ return $this->call('flickr.places.getChildrenWithPhotosPublic', array('place_id' => $place_id, 'woe_id' => $woe_id));
+ }
+
+ function places_getInfo ($place_id = NULL, $woe_id = NULL) {
+ /* http://www.flickr.com/services/api/flickr.places.getInfo.html */
+ return $this->call('flickr.places.getInfo', array('place_id' => $place_id, 'woe_id' => $woe_id));
+ }
+
+ function places_getInfoByUrl ($url) {
+ /* http://www.flickr.com/services/api/flickr.places.getInfoByUrl.html */
+ return $this->call('flickr.places.getInfoByUrl', array('url' => $url));
+ }
+
+ function places_getPlaceTypes () {
+ /* http://www.flickr.com/services/api/flickr.places.getPlaceTypes.html */
+ return $this->call('flickr.places.getPlaceTypes', array());
+ }
+
+ function places_getShapeHistory ($place_id = NULL, $woe_id = NULL) {
+ /* http://www.flickr.com/services/api/flickr.places.getShapeHistory.html */
+ return $this->call('flickr.places.getShapeHistory', array('place_id' => $place_id, 'woe_id' => $woe_id));
+ }
+
+ function places_getTopPlacesList ($place_type_id, $date = NULL, $woe_id = NULL, $place_id = NULL) {
+ /* http://www.flickr.com/services/api/flickr.places.getTopPlacesList.html */
+ return $this->call('flickr.places.getTopPlacesList', array('place_type_id' => $place_type_id, 'date' => $date, 'woe_id' => $woe_id, 'place_id' => $place_id));
+ }
+
+ function places_placesForBoundingBox ($bbox, $place_type = NULL, $place_type_id = NULL, $recursive = NULL) {
+ /* http://www.flickr.com/services/api/flickr.places.placesForBoundingBox.html */
+ return $this->call('flickr.places.placesForBoundingBox', array('bbox' => $bbox, 'place_type' => $place_type, 'place_type_id' => $place_type_id, 'recursive' => $recursive));
+ }
+
+ function places_placesForContacts ($place_type = NULL, $place_type_id = NULL, $woe_id = NULL, $place_id = NULL, $threshold = NULL, $contacts = NULL, $min_upload_date = NULL, $max_upload_date = NULL, $min_taken_date = NULL, $max_taken_date = NULL) {
+ /* http://www.flickr.com/services/api/flickr.places.placesForContacts.html */
+ return $this->call('flickr.places.placesForContacts', array('place_type' => $place_type, 'place_type_id' => $place_type_id, 'woe_id' => $woe_id, 'place_id' => $place_id, 'threshold' => $threshold, 'contacts' => $contacts, 'min_upload_date' => $min_upload_date, 'max_upload_date' => $max_upload_date, 'min_taken_date' => $min_taken_date, 'max_taken_date' => $max_taken_date));
+ }
+
+ function places_placesForTags ($place_type_id, $woe_id = NULL, $place_id = NULL, $threshold = NULL, $tags = NULL, $tag_mode = NULL, $machine_tags = NULL, $machine_tag_mode = NULL, $min_upload_date = NULL, $max_upload_date = NULL, $min_taken_date = NULL, $max_taken_date = NULL) {
+ /* http://www.flickr.com/services/api/flickr.places.placesForTags.html */
+ return $this->call('flickr.places.placesForTags', array('place_type_id' => $place_type_id, 'woe_id' => $woe_id, 'place_id' => $place_id, 'threshold' => $threshold, 'tags' => $tags, 'tag_mode' => $tag_mode, 'machine_tags' => $machine_tags, 'machine_tag_mode' => $machine_tag_mode, 'min_upload_date' => $min_upload_date, 'max_upload_date' => $max_upload_date, 'min_taken_date' => $min_taken_date, 'max_taken_date' => $max_taken_date));
+ }
+
+ function places_placesForUser ($place_type_id = NULL, $place_type = NULL, $woe_id = NULL, $place_id = NULL, $threshold = NULL, $min_upload_date = NULL, $max_upload_date = NULL, $min_taken_date = NULL, $max_taken_date = NULL) {
+ /* http://www.flickr.com/services/api/flickr.places.placesForUser.html */
+ return $this->call('flickr.places.placesForUser', array('place_type_id' => $place_type_id, 'place_type' => $place_type, 'woe_id' => $woe_id, 'place_id' => $place_id, 'threshold' => $threshold, 'min_upload_date' => $min_upload_date, 'max_upload_date' => $max_upload_date, 'min_taken_date' => $min_taken_date, 'max_taken_date' => $max_taken_date));
+ }
+
+ function places_resolvePlaceId ($place_id) {
+ /* http://www.flickr.com/services/api/flickr.places.resolvePlaceId.html */
+ $rsp = $this->call('flickr.places.resolvePlaceId', array('place_id' => $place_id));
+ return $rsp ? $rsp['location'] : $rsp;
+ }
+
+ function places_resolvePlaceURL ($url) {
+ /* http://www.flickr.com/services/api/flickr.places.resolvePlaceURL.html */
+ $rsp = $this->call('flickr.places.resolvePlaceURL', array('url' => $url));
+ return $rsp ? $rsp['location'] : $rsp;
+ }
+
+ function places_tagsForPlace ($woe_id = NULL, $place_id = NULL, $min_upload_date = NULL, $max_upload_date = NULL, $min_taken_date = NULL, $max_taken_date = NULL) {
+ /* http://www.flickr.com/services/api/flickr.places.tagsForPlace.html */
+ return $this->call('flickr.places.tagsForPlace', array('woe_id' => $woe_id, 'place_id' => $place_id, 'min_upload_date' => $min_upload_date, 'max_upload_date' => $max_upload_date, 'min_taken_date' => $min_taken_date, 'max_taken_date' => $max_taken_date));
+ }
+
+ /* Prefs Methods */
+ function prefs_getContentType () {
+ /* http://www.flickr.com/services/api/flickr.prefs.getContentType.html */
+ $rsp = $this->call('flickr.prefs.getContentType', array());
+ return $rsp ? $rsp['person'] : $rsp;
+ }
+
+ function prefs_getGeoPerms () {
+ /* http://www.flickr.com/services/api/flickr.prefs.getGeoPerms.html */
+ return $this->call('flickr.prefs.getGeoPerms', array());
+ }
+
+ function prefs_getHidden () {
+ /* http://www.flickr.com/services/api/flickr.prefs.getHidden.html */
+ $rsp = $this->call('flickr.prefs.getHidden', array());
+ return $rsp ? $rsp['person'] : $rsp;
+ }
+
+ function prefs_getPrivacy () {
+ /* http://www.flickr.com/services/api/flickr.prefs.getPrivacy.html */
+ $rsp = $this->call('flickr.prefs.getPrivacy', array());
+ return $rsp ? $rsp['person'] : $rsp;
+ }
+
+ function prefs_getSafetyLevel () {
+ /* http://www.flickr.com/services/api/flickr.prefs.getSafetyLevel.html */
+ $rsp = $this->call('flickr.prefs.getSafetyLevel', array());
+ return $rsp ? $rsp['person'] : $rsp;
+ }
+
+ /* Reflection Methods */
+ function reflection_getMethodInfo ($method_name) {
+ /* http://www.flickr.com/services/api/flickr.reflection.getMethodInfo.html */
+ $this->request("flickr.reflection.getMethodInfo", array("method_name" => $method_name));
+ return $this->parsed_response ? $this->parsed_response : false;
+ }
+
+ function reflection_getMethods () {
+ /* http://www.flickr.com/services/api/flickr.reflection.getMethods.html */
+ $this->request("flickr.reflection.getMethods");
+ return $this->parsed_response ? $this->parsed_response['methods']['method'] : false;
+ }
+
+ /* Stats Methods */
+ function stats_getCollectionDomains ($date, $collection_id = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.stats.getCollectionDomains.html */
+ return $this->call('flickr.stats.getCollectionDomains', array('date' => $date, 'collection_id' => $collection_id, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function stats_getCollectionReferrers ($date, $domain, $collection_id = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.stats.getCollectionReferrers.html */
+ return $this->call('flickr.stats.getCollectionReferrers', array('date' => $date, 'domain' => $domain, 'collection_id' => $collection_id, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function stats_getCollectionStats ($date, $collection_id) {
+ /* http://www.flickr.com/services/api/flickr.stats.getCollectionStats.html */
+ return $this->call('flickr.stats.getCollectionStats', array('date' => $date, 'collection_id' => $collection_id));
+ }
+
+ function stats_getCSVFiles () {
+ /* http://www.flickr.com/services/api/flickr.stats.getCSVFiles.html */
+ return $this->call('flickr.stats.getCSVFiles', array());
+ }
+
+ function stats_getPhotoDomains ($date, $photo_id = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.stats.getPhotoDomains.html */
+ return $this->call('flickr.stats.getPhotoDomains', array('date' => $date, 'photo_id' => $photo_id, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function stats_getPhotoReferrers ($date, $domain, $photo_id = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.stats.getPhotoReferrers.html */
+ return $this->call('flickr.stats.getPhotoReferrers', array('date' => $date, 'domain' => $domain, 'photo_id' => $photo_id, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function stats_getPhotosetDomains ($date, $photoset_id = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.stats.getPhotosetDomains.html */
+ return $this->call('flickr.stats.getPhotosetDomains', array('date' => $date, 'photoset_id' => $photoset_id, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function stats_getPhotosetReferrers ($date, $domain, $photoset_id = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.stats.getPhotosetReferrers.html */
+ return $this->call('flickr.stats.getPhotosetReferrers', array('date' => $date, 'domain' => $domain, 'photoset_id' => $photoset_id, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function stats_getPhotosetStats ($date, $photoset_id) {
+ /* http://www.flickr.com/services/api/flickr.stats.getPhotosetStats.html */
+ return $this->call('flickr.stats.getPhotosetStats', array('date' => $date, 'photoset_id' => $photoset_id));
+ }
+
+ function stats_getPhotoStats ($date, $photo_id) {
+ /* http://www.flickr.com/services/api/flickr.stats.getPhotoStats.html */
+ return $this->call('flickr.stats.getPhotoStats', array('date' => $date, 'photo_id' => $photo_id));
+ }
+
+ function stats_getPhotostreamDomains ($date, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.stats.getPhotostreamDomains.html */
+ return $this->call('flickr.stats.getPhotostreamDomains', array('date' => $date, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function stats_getPhotostreamReferrers ($date, $domain, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.stats.getPhotostreamReferrers.html */
+ return $this->call('flickr.stats.getPhotostreamReferrers', array('date' => $date, 'domain' => $domain, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function stats_getPhotostreamStats ($date) {
+ /* http://www.flickr.com/services/api/flickr.stats.getPhotostreamStats.html */
+ return $this->call('flickr.stats.getPhotostreamStats', array('date' => $date));
+ }
+
+ function stats_getPopularPhotos ($date = NULL, $sort = NULL, $per_page = NULL, $page = NULL) {
+ /* http://www.flickr.com/services/api/flickr.stats.getPopularPhotos.html */
+ return $this->call('flickr.stats.getPopularPhotos', array('date' => $date, 'sort' => $sort, 'per_page' => $per_page, 'page' => $page));
+ }
+
+ function stats_getTotalViews ($date = NULL) {
+ /* http://www.flickr.com/services/api/flickr.stats.getTotalViews.html */
+ return $this->call('flickr.stats.getTotalViews', array('date' => $date));
+ }
+
+ /* Tags Methods */
+ function tags_getClusterPhotos ($tag, $cluster_id) {
+ /* http://www.flickr.com/services/api/flickr.tags.getClusterPhotos.html */
+ return $this->call('flickr.tags.getClusterPhotos', array('tag' => $tag, 'cluster_id' => $cluster_id));
+ }
+
+ function tags_getClusters ($tag) {
+ /* http://www.flickr.com/services/api/flickr.tags.getClusters.html */
+ return $this->call('flickr.tags.getClusters', array('tag' => $tag));
+ }
+
+ function tags_getHotList ($period = NULL, $count = NULL) {
+ /* http://www.flickr.com/services/api/flickr.tags.getHotList.html */
+ $this->request("flickr.tags.getHotList", array("period" => $period, "count" => $count));
+ return $this->parsed_response ? $this->parsed_response['hottags'] : false;
+ }
+
+ function tags_getListPhoto ($photo_id) {
+ /* http://www.flickr.com/services/api/flickr.tags.getListPhoto.html */
+ $this->request("flickr.tags.getListPhoto", array("photo_id" => $photo_id));
+ return $this->parsed_response ? $this->parsed_response['photo']['tags']['tag'] : false;
+ }
+
+ function tags_getListUser ($user_id = NULL) {
+ /* http://www.flickr.com/services/api/flickr.tags.getListUser.html */
+ $this->request("flickr.tags.getListUser", array("user_id" => $user_id));
+ return $this->parsed_response ? $this->parsed_response['who']['tags']['tag'] : false;
+ }
+
+ function tags_getListUserPopular ($user_id = NULL, $count = NULL) {
+ /* http://www.flickr.com/services/api/flickr.tags.getListUserPopular.html */
+ $this->request("flickr.tags.getListUserPopular", array("user_id" => $user_id, "count" => $count));
+ return $this->parsed_response ? $this->parsed_response['who']['tags']['tag'] : false;
+ }
+
+ function tags_getListUserRaw ($tag = NULL) {
+ /* http://www.flickr.com/services/api/flickr.tags.getListUserRaw.html */
+ return $this->call('flickr.tags.getListUserRaw', array('tag' => $tag));
+ }
+
+ function tags_getRelated ($tag) {
+ /* http://www.flickr.com/services/api/flickr.tags.getRelated.html */
+ $this->request("flickr.tags.getRelated", array("tag" => $tag));
+ return $this->parsed_response ? $this->parsed_response['tags'] : false;
+ }
+
+ function test_echo ($args = array()) {
+ /* http://www.flickr.com/services/api/flickr.test.echo.html */
+ $this->request("flickr.test.echo", $args);
+ return $this->parsed_response ? $this->parsed_response : false;
+ }
+
+ function test_login () {
+ /* http://www.flickr.com/services/api/flickr.test.login.html */
+ $this->request("flickr.test.login");
+ return $this->parsed_response ? $this->parsed_response['user'] : false;
+ }
+
+ function urls_getGroup ($group_id) {
+ /* http://www.flickr.com/services/api/flickr.urls.getGroup.html */
+ $this->request("flickr.urls.getGroup", array("group_id"=>$group_id));
+ return $this->parsed_response ? $this->parsed_response['group']['url'] : false;
+ }
+
+ function urls_getUserPhotos ($user_id = NULL) {
+ /* http://www.flickr.com/services/api/flickr.urls.getUserPhotos.html */
+ $this->request("flickr.urls.getUserPhotos", array("user_id"=>$user_id));
+ return $this->parsed_response ? $this->parsed_response['user']['url'] : false;
+ }
+
+ function urls_getUserProfile ($user_id = NULL) {
+ /* http://www.flickr.com/services/api/flickr.urls.getUserProfile.html */
+ $this->request("flickr.urls.getUserProfile", array("user_id"=>$user_id));
+ return $this->parsed_response ? $this->parsed_response['user']['url'] : false;
+ }
+
+ function urls_lookupGallery ($url) {
+ /* http://www.flickr.com/services/api/flickr.urls.lookupGallery.html */
+ return $this->call('flickr.urls.lookupGallery', array('url' => $url));
+ }
+
+ function urls_lookupGroup ($url) {
+ /* http://www.flickr.com/services/api/flickr.urls.lookupGroup.html */
+ $this->request("flickr.urls.lookupGroup", array("url"=>$url));
+ return $this->parsed_response ? $this->parsed_response['group'] : false;
+ }
+
+ function urls_lookupUser ($url) {
+ /* http://www.flickr.com/services/api/flickr.photos.notes.edit.html */
+ $this->request("flickr.urls.lookupUser", array("url"=>$url));
+ return $this->parsed_response ? $this->parsed_response['user'] : false;
+ }
+ }
+}
+
+if ( !class_exists('phpFlickr_pager') ) {
+ class phpFlickr_pager {
+ var $phpFlickr, $per_page, $method, $args, $results, $global_phpFlickr;
+ var $total = null, $page = 0, $pages = null, $photos, $_extra = null;
+
+
+ function phpFlickr_pager($phpFlickr, $method = null, $args = null, $per_page = 30) {
+ $this->per_page = $per_page;
+ $this->method = $method;
+ $this->args = $args;
+ $this->set_phpFlickr($phpFlickr);
+ }
+
+ function set_phpFlickr($phpFlickr) {
+ if ( is_a($phpFlickr, 'phpFlickr') ) {
+ $this->phpFlickr = $phpFlickr;
+ if ( $this->phpFlickr->cache ) {
+ $this->args['per_page'] = 500;
+ } else {
+ $this->args['per_page'] = (int) $this->per_page;
+ }
+ }
+ }
+
+ function __sleep() {
+ return array(
+ 'method',
+ 'args',
+ 'per_page',
+ 'page',
+ '_extra',
+ );
+ }
+
+ function load($page) {
+ $allowed_methods = array(
+ 'flickr.photos.search' => 'photos',
+ 'flickr.photosets.getPhotos' => 'photoset',
+ );
+ if ( !in_array($this->method, array_keys($allowed_methods)) ) return false;
+
+ if ( $this->phpFlickr->cache ) {
+ $min = ($page - 1) * $this->per_page;
+ $max = $page * $this->per_page - 1;
+ if ( floor($min/500) == floor($max/500) ) {
+ $this->args['page'] = floor($min/500) + 1;
+ $this->results = $this->phpFlickr->call($this->method, $this->args);
+ if ( $this->results ) {
+ $this->results = $this->results[$allowed_methods[$this->method]];
+ $this->photos = array_slice($this->results['photo'], $min % 500, $this->per_page);
+ $this->total = $this->results['total'];
+ $this->pages = ceil($this->results['total'] / $this->per_page);
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ $this->args['page'] = floor($min/500) + 1;
+ $this->results = $this->phpFlickr->call($this->method, $this->args);
+ if ( $this->results ) {
+ $this->results = $this->results[$allowed_methods[$this->method]];
+
+ $this->photos = array_slice($this->results['photo'], $min % 500);
+ $this->total = $this->results['total'];
+ $this->pages = ceil($this->results['total'] / $this->per_page);
+
+ $this->args['page'] = floor($min/500) + 2;
+ $this->results = $this->phpFlickr->call($this->method, $this->args);
+ if ( $this->results ) {
+ $this->results = $this->results[$allowed_methods[$this->method]];
+ $this->photos = array_merge($this->photos, array_slice($this->results['photo'], 0, $max % 500 + 1));
+ }
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+ } else {
+ $this->args['page'] = $page;
+ $this->results = $this->phpFlickr->call($this->method, $this->args);
+ if ( $this->results ) {
+ $this->results = $this->results[$allowed_methods[$this->method]];
+
+ $this->photos = $this->results['photo'];
+ $this->total = $this->results['total'];
+ $this->pages = $this->results['pages'];
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ function get($page = null) {
+ if ( is_null($page) ) {
+ $page = $this->page;
+ } else {
+ $this->page = $page;
+ }
+ if ( $this->load($page) ) {
+ return $this->photos;
+ }
+ $this->total = 0;
+ $this->pages = 0;
+ return array();
+ }
+
+ function next() {
+ $this->page++;
+ if ( $this->load($this->page) ) {
+ return $this->photos;
+ }
+ $this->total = 0;
+ $this->pages = 0;
+ return array();
+ }
+
+ }
+}
+
+?>
diff --git a/web/lib/instagram_api/.gitignore b/web/lib/instagram_api/.gitignore
new file mode 100644
index 0000000..aedafa6
--- /dev/null
+++ b/web/lib/instagram_api/.gitignore
@@ -0,0 +1,3 @@
+/config.xml
+tmp/
+.DS_Store
\ No newline at end of file
diff --git a/web/lib/instagram_api/.travis.yml b/web/lib/instagram_api/.travis.yml
new file mode 100644
index 0000000..bb17424
--- /dev/null
+++ b/web/lib/instagram_api/.travis.yml
@@ -0,0 +1,8 @@
+language: php
+php:
+ - 5.3
+ - 5.4
+branches:
+ only:
+ - master
+ - development
\ No newline at end of file
diff --git a/web/lib/instagram_api/LICENSE b/web/lib/instagram_api/LICENSE
new file mode 100644
index 0000000..31e052d
--- /dev/null
+++ b/web/lib/instagram_api/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2011 randy sesser
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/web/lib/instagram_api/README.md b/web/lib/instagram_api/README.md
new file mode 100644
index 0000000..059a3f9
--- /dev/null
+++ b/web/lib/instagram_api/README.md
@@ -0,0 +1,111 @@
+## Instaphp v1.0
+
+This software is licensed under The MIT License. Please see the file named 'LICENSE' for futher details.
+
+### About
+Instaphp is a small(ish) PHP library to access [Instagram's][0] [API][1]. It's
+main goal was to be easy to use, lightweight and have as few dependencies as
+possible. It's currently only compatible with PHP 5 >= 5.3 but there are
+very few 5.3 features being used and it's relatively trivial to convert it
+to versions < 5.3.
+
+Instaphp is currently being used to power [instaview.me](http://instaview.me).
+
+### Quickstart Guide
+To get an idea of how the library works, it's best to understand the various
+[endpoints][2] provided by the API itself. The Instagram API currently has eight
+"endpoints" in which to retrieve data from their system:
+
+* Users
+* Relationships
+* Media
+* Comments
+* Likes
+* Tags
+* Locations
+* Geographies (This is really a subscription based endpoint and not available in Instaphp, yet)
+
+In actuality, these eight endpoints can be summarized into four major endpoints:
+
+* Users
+* Media
+* Tags
+* Locations
+
+Relationships are really an attribute of Users. Comments and Likes are both
+attributes of Media. Geographies are also an attribute of Media however, that
+particular endpoint is only available for subscriptions created for a particular
+location. Currently, Instaphp does not have a mechanism that supports subscriptions.
+
+These four main "endpoints" are the basis for this library and allows a good
+separation for the various data you can pull from Instagram.
+
+#### Example: Getting the current Popular photos
+
+```php
+Media->Popular();
+
+//-- Check if an error was returned from the API
+if (empty($response->error))
+ foreach ($response->data as $item)
+ printf('', $item->images->thumbnail->url, $item->images->thumbnail->width, $item->images->thumbnail->height, empty($item->caption->text) ? 'Untitled':$item->caption->text);
+```
+
+#### Example: Authentication
+
+Instagram uses oAuth to authenticate its users. That means you follow a link to
+their site, login to their system, and grant an application access on your behalf.
+It's a fairly common scheme for handling authentication without passing sensitive
+data (e.g. your username and password) across (possibly) unsecure lines (e.g. non-https).
+
+For Instaphp, you must have an API Key, API Secret and callback URL in order for
+oAuth to work. The basic flow looks like this:
+
+1. User clicks a link to "Login"
+2. User lands on Instagram's site and enters username/password
+3. Upon successful login, user is asked if they want to grant application access to their photos
+4. If user allows access, Instagram redirects user to callback URL of application with a code
+5. Application calls API with code to validate authentication
+6. Application is then given an access token to "sign" the calls to the API
+
+Here's how it looks:
+
+```php
+GetOAuthUri(); ?>
+
+
+ Login
+
+ Users->Authenticate($code);
+
+ //-- If no errors, grab the access_token (and cookie it, if desired)
+ if (empty($response->error)) {
+ $token = $response->auth->access_token;
+ setcookie('instaphp', $token, strtotime('30 days'));
+ //-- once you have a token, update the Instaphp instance so it passes the token for future calls
+ $api = Instaphp\Instaphp::Instance($token);
+ }
+ }
+```
+
+[0]: http://instagr.am/
+[1]: http://instagram.com/developer/
+[2]: http://instagram.com/developer/endpoints/
diff --git a/web/lib/instagram_api/config.php b/web/lib/instagram_api/config.php
new file mode 100644
index 0000000..4cf04fa
--- /dev/null
+++ b/web/lib/instagram_api/config.php
@@ -0,0 +1,145 @@
+
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author randy sesser
+ * @copyright 2011, randy sesser
+ * @license http://www.opensource.org/licenses/mit-license The MIT License
+ * @package Instaphp
+ * @filesource
+ */
+
+namespace Instaphp {
+
+ use \SimpleXMLElement;
+
+ /**
+ * The Instaphp version. We pass this to Instagram as part of the User-Agent
+ */
+ define('INSTAPHP_VERSION', '1.0');
+
+ /**
+ * Our Config class which extends the SimpleXMLElement class
+ * See {inline @link http://php.net/simplexmlelement SimplXMLElement}
+ * @package Instaphp
+ * @version 1.0
+ * @author randy sesser
+ */
+ class Config extends SimpleXMLElement
+ {
+
+ /**
+ * A static instance property for creating an instance of the Config object
+ * @var Instaphp\Config
+ * @access private
+ */
+ private static $_instance = null;
+ /**
+ * The path to the config.xml file
+ * @var string
+ * @access private
+ */
+ private static $file = null;
+
+ /**
+ * Singleton method since the SimpleXMLElement class is essentially "sealed"
+ * @return Config An instance of the Config object
+ */
+ public static function Instance()
+ {
+ if (static::$file == null)
+ static::$file = realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'config.xml';
+
+ if (!file_exists(static::$file)) {
+ trigger_error("No configuration found for Instaphp. Using sample file!", E_USER_WARNING);
+ static::$file = realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'config.xml';
+ }
+
+ if (null == static::$_instance)
+ static::$_instance = new self(static::$file, null, true);
+
+ return static::$_instance;
+ }
+
+ /**
+ * A convenience method to build the OAuth URL to authenticate a user.
+ * the value in the config.xml file should contain some "tokens" that
+ * are replaced with other values in the config.
+ * @access public
+ * @return string The OAuth URL used to authenticate a user
+ */
+ public function GetOAuthUri()
+ {
+ if (!isset($this->Instagram))
+ return null;
+
+ $path = $this->Instagram->OAuthPath;
+ $path = str_replace("{ClientId}", $this->Instagram->ClientId, $path);
+ $path = str_replace("{RedirectUri}", $this->Instaphp->RedirectUri, $path);
+
+ if (!empty($this->Instagram->Scope))
+ $path .= '&scope=' . $this->Instagram->Scope;
+
+ return $this->Instagram->Endpoint . $path;
+ }
+
+ /**
+ * A convenience method to build the OAuth URL used to retreive an access token
+ * @return string The URL used to retrieve the access token
+ */
+ public function GetOAuthTokenUri()
+ {
+ if (!isset($this->Instagram))
+ return null;
+
+ return $this->Instagram->Endpoint . $this->Instagram->OAuthTokenPath;
+ }
+
+ public function CacheSetting($name, $key)
+ {
+ $cache = $this->xpath("//Instaphp/Cache[@Engine='File']");
+ if (empty($cache) || count($cache) == 0)
+ return null;
+
+ $cache = $cache[0];
+
+ return $cache->Settings->Setting[$key];
+
+ }
+
+ public function GetSection($section = null, \SimpleXMLElement $parent = null)
+ {
+ if (empty($section))
+ return null;
+
+ if (null !== $parent)
+ return $parent->xpath($section);
+
+ return $this->xpath($section);
+ }
+
+ }
+
+}
+
diff --git a/web/lib/instagram_api/instagram/instagrambase.php b/web/lib/instagram_api/instagram/instagrambase.php
new file mode 100644
index 0000000..e3a6832
--- /dev/null
+++ b/web/lib/instagram_api/instagram/instagrambase.php
@@ -0,0 +1,231 @@
+
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author randy sesser
+ * @copyright 2011, randy sesser
+ * @license http://www.opensource.org/licenses/mit-license The MIT License
+ * @package Instaphp
+ * @filesource
+ */
+
+namespace Instaphp\Instagram {
+
+ use Instaphp\Config;
+ use Instaphp\Request;
+ use Instaphp\Response;
+
+ /**
+ * Instaphp Base Instagram class.
+ * @package Instaphp
+ * @version 1.0
+ * @author randy
+ */
+ class InstagramBase
+ {
+
+ /**
+ * The Instaphp Config object
+ * @var Config
+ * @access protected
+ */
+ protected $config = null;
+ /**
+ * The base API path appended to the endpoint
+ * @var string
+ * @access protected
+ */
+ protected $api_path;
+ /**
+ * Parameters passed to the API
+ * @var Array
+ * @access protected
+ */
+ protected $default_params = array();
+ /**
+ * The access token used to authenticate API calls
+ * @var string
+ * @access protected
+ */
+ protected $access_token;
+ /**
+ * Our request object
+ * @var Request
+ * @access protected
+ */
+ protected $request;
+
+ /**
+ * THE parameters array passed to the API call
+ *
+ * @var array
+ * @access public
+ */
+ public $parameters = array();
+
+ /**
+ * Constructor.
+ * If you inherit from this class, you must call the parent constructor
+ * @access public
+ */
+ public function __construct($token = null)
+ {
+ $this->config = Config::Instance();
+ $this->default_params['client_id'] = $this->config->Instagram->ClientId;
+
+ if (!empty($token))
+ $this->default_params['access_token'] = $token;
+
+ $this->request = new Request();
+ }
+
+ /**
+ * A convenience method for making Get requests via the request
+ * @access protected
+ * @param string $url A url in which to make a request
+ * @param Array $params An associative array of key/value pairs to pass to the API
+ * @return Response
+ */
+ protected function Get($url = null, $params = array())
+ {
+ if (empty($url))
+ trigger_error('A URL is required in ' . __METHOD__, E_USER_ERROR);
+
+ if (!empty($params))
+ $this->AddParams($params);
+
+ return $this->request->Get($url, array_merge($this->default_params, $this->parameters))->response;
+ }
+
+ /**
+ * A convenience method for making POST request via the request object
+ * @access protected
+ * @param string $url A url in which to make a POST request
+ * @param Array $params An associative array of key/value pairs to POST to the API
+ * @return Response
+ */
+ protected function Post($url = null, $params = array())
+ {
+ if (empty($url))
+ trigger_error('A URL is required in ' . __METHOD__, E_USER_ERROR);
+
+ if (!empty($params))
+ $this->AddParams($params);
+
+ return $this->request->Post($url, array_merge($this->default_params, $this->parameters))->response;
+ }
+
+ /**
+ * A convenience method for making DELETE requests via the request object
+ * @access protected
+ * @param string $url A url in which to make a DELETE request
+ * @param Array $params An associative array of key/value pairs to pass to the API
+ * @return Response
+ */
+ protected function Delete($url = null, $params = array())
+ {
+ if (empty($url))
+ trigger_error('A URL is required in ' . __METHOD__, E_USER_ERROR);
+
+ if (!empty($params))
+ $this->AddParams($params);
+
+ return $this->request->Delete($url, array_merge($this->default_params, $this->parameters))->response;
+ }
+
+ /**
+ * A convenience method that builds a base URL to the Instagram API based on
+ * values in the config.xml file and the $api_path property.
+ * @access protected
+ * @param string $path The path to append to the base URL to create the endpoint
+ * @param string $action The 'action' to append to the endpoint (not always used, but available)
+ * @return string The Instagram API endpoint
+ */
+ protected function BuildUrl($path = null, $action = null)
+ {
+ $uri = $this->config->Instagram->Endpoint . '/' . $this->config->Instagram->Version;
+
+
+ if (!empty($path) && substr($path, 0, 1) !== '/')
+ $path = '/' . $path;
+
+ $path = $this->api_path . $path;
+
+ $uri .= $path;
+
+ if (null !== $action) {
+ if (substr($action, 0, 1) !== '/')
+ $action = '/' . $action;
+
+ if (substr($action, strlen($action) - 1, 1) !== '/')
+ $action .= '/';
+
+ $uri .= $action;
+ }
+
+ return $uri;
+ }
+
+ /**
+ * A convenience method for bulk adding querystring parameters
+ * to the API requests. Note that existing params will be over-written.
+ * @access public
+ * @param Array $params Associative array of key/value pairs to add
+ * @return void
+ */
+ public function AddParams(Array $params = array())
+ {
+ $this->parameters = $params;
+ }
+
+ /**
+ * A convenience method for adding a single parameter to the querystring
+ * passed to the API. Note this will overwrite existing parameters with
+ * the same name.
+ * @access public
+ * @param string $name The parameter name
+ * @param string $value The value to pass
+ * @return void
+ */
+ public function AddParam($name, $value)
+ {
+ if (!empty($name))
+ $this->parameters[$name] = $value;
+ }
+
+ /**
+ * A convenience method for removing parameters from the querystring.
+ * @access public
+ * @param string $name The name of the parameter to remove
+ * @return void
+ */
+ public function RemoveParam($name)
+ {
+ if (isset($this->parameters[$name]))
+ unset($this->parameters[$name]);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/web/lib/instagram_api/instagram/locations.php b/web/lib/instagram_api/instagram/locations.php
new file mode 100644
index 0000000..0b95c9c
--- /dev/null
+++ b/web/lib/instagram_api/instagram/locations.php
@@ -0,0 +1,109 @@
+
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author randy sesser
+ * @copyright 2011, randy sesser
+ * @license http://www.opensource.org/licenses/mit-license The MIT License
+ * @package Instaphp
+ * @filesource
+ */
+
+namespace Instaphp\Instagram {
+
+ use Instaphp\Config;
+ use Instaphp\Request;
+ use Instaphp\Response;
+
+ /**
+ * Locations class
+ * Handles all Location based API requests
+ * @package Instaphp
+ * @version 1.0
+ * @author randy sesser
+ */
+ class Locations extends InstagramBase
+ {
+
+ public function __construct($token = null)
+ {
+ parent::__construct($token);
+ $this->api_path = '/locations';
+ }
+
+ /**
+ * Gets information about a particular location
+ * @access public
+ * @param int $location_id A location ID
+ * @param string $token An access token
+ * @return Response
+ */
+ public function Info($location_id)
+ {
+ return $this->Get($this->buildUrl($location_id));
+ }
+
+ /**
+ * Get recent media associated with a particular media
+ * @access public
+ * @param int $location_id A location ID
+ * @param string $token An access token
+ * @param Array $params An associative array of key/value pairs to pass to the API
+ * @return Response
+ */
+ public function Recent($location_id, Array $params = array())
+ {
+ if (!empty($params))
+ $this->AddParams($params);
+
+ return $this->Get($this->buildUrl($location_id . '/media/recent'));
+ }
+
+ /**
+ * Search for media by latitude/longitude
+ * @access public
+ * @param string $token An access token
+ * @param Array $params An associative array of key/value pairs to pass to the API
+ * @return Response
+ */
+ public function Search(Array $params = array())
+ {
+ if (isset($params['lat'])) {
+ if (!isset($params['lng']) || empty($params['lng']))
+ trigger_error('Longitude and Latitude are mutually inclusive in ' . __METHOD__, E_USER_ERROR);
+ }
+ if (isset($params['lng'])) {
+ if (!isset($params['lat']) || empty($params['lat']))
+ trigger_error('Longitude and Latitude are mutually inclusive in ' . __METHOD__, E_USER_ERROR);
+ }
+
+ if (!empty($params))
+ $this->AddParams($params);
+
+ return $this->Get($this->buildUrl('search'));
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/web/lib/instagram_api/instagram/media.php b/web/lib/instagram_api/instagram/media.php
new file mode 100644
index 0000000..06f6dd9
--- /dev/null
+++ b/web/lib/instagram_api/instagram/media.php
@@ -0,0 +1,185 @@
+
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author randy sesser
+ * @copyright 2011, randy sesser
+ * @license http://www.opensource.org/licenses/mit-license The MIT License
+ * @package Instaphp
+ * @filesource
+ */
+
+namespace Instaphp\Instagram {
+
+ use Instaphp\Config;
+ use Instaphp\Request;
+ use Instaphp\Response;
+
+ /**
+ * Media
+ * The Media class handles all media requests to the API
+ * @package Instaphp
+ * @version 1.0
+ * @author randy sesser
+ */
+ class Media extends InstagramBase
+ {
+ public function __construct($token = null)
+ {
+ parent::__construct($token);
+ $this->api_path = '/media';
+ }
+
+ /**
+ * Gets information about a particular media
+ * @access public
+ * @param int $media_id A media ID
+ * @param string $token An access token
+ * @return Response
+ */
+ public function Info($media_id)
+ {
+ return $this->Get($this->buildUrl($media_id));
+ }
+
+ /**
+ * Searches the API
+ * @access public
+ * @param string $token An access token
+ * @param Array $params An associative array of key/value pairs to pass to the API
+ * @return Response
+ */
+ public function Search(Array $params = array())
+ {
+
+ if (isset($params['lat'])) {
+ if (!isset($params['lng']) || empty($params['lng']))
+ trigger_error('Longitude and Latitude are mutually inclusive in ' . __METHOD__, E_USER_ERROR);
+ }
+ if (isset($params['lng'])) {
+ if (!isset($params['lat']) || empty($params['lat']))
+ trigger_error('Longitude and Latitude are mutually inclusive in ' . __METHOD__, E_USER_ERROR);
+ }
+
+ if (!empty($params))
+ $this->AddParams($params);
+
+ return $this->Get($this->buildUrl('search'));
+ }
+
+ public function OEmbed($url)
+ {
+ $uri = $this->config->Instagram->Endpoint . '/' . $this->config->Instagram->Version;
+ return $this->Get($uri.'/oembed', array('url' => $url));
+ }
+
+ /**
+ * Gets the recent popular media.
+ * Note: This method does not appear to require authentication
+ * @access public
+ * @return Response
+ */
+ public function Popular()
+ {
+ return $this->Get($this->BuildUrl('popular'));
+ }
+
+ /**
+ * Gets comments associated with a particular media
+ * @access public
+ * @param int $media_id A media ID
+ * @param string $token An access token
+ * @return Response
+ */
+ public function Comments($media_id)
+ {
+ return $this->Get($this->buildUrl($media_id . '/comments'));
+ }
+
+ /**
+ * Adds a comment to a particular media
+ * @access public
+ * @param int $media_id A media ID
+ * @param string $comment The text of the comment
+ * @param string $token An access token
+ * @return Response
+ */
+ public function Comment($media_id, $comment)
+ {
+ $this->AddParam('text', $comment);
+ return $this->Post($this->buildUrl($media_id . '/comments'));
+ }
+
+ /**
+ * Deletes a comment previously left on a particular media
+ * @access public
+ * @param int $media_id A media ID
+ * @param int $comment_id The comment ID to delete
+ * @param string $token An access token
+ * @return Response
+ */
+ public function DeleteComment($media_id, $comment_id)
+ {
+ return $this->Delete($this->buildUrl($media_id . '/comments/' . $comment_id));
+ }
+
+ /**
+ * Gets likes for a particular media
+ * @access public
+ * @param int $media_id A media ID
+ * @param string $token An access token
+ * @return Response
+ */
+ public function Likes($media_id)
+ {
+ return $this->Get($this->buildUrl($media_id . '/likes'));
+ }
+
+ /**
+ * Likes a particular media
+ * @access public
+ * @param int $media_id A media ID
+ * @param string $token An access token
+ * @return Response
+ */
+ public function Like($media_id)
+ {
+ return $this->Post($this->buildUrl($media_id . '/likes'));
+ }
+
+ /**
+ * Unlikes a particular media
+ * @access public
+ * @param int $media_id A media ID
+ * @param string $token An access token
+ * @return Response
+ */
+ public function Unlike($media_id)
+ {
+ return $this->Delete($this->buildUrl($media_id . '/likes'));
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/web/lib/instagram_api/instagram/tags.php b/web/lib/instagram_api/instagram/tags.php
new file mode 100644
index 0000000..b3209b7
--- /dev/null
+++ b/web/lib/instagram_api/instagram/tags.php
@@ -0,0 +1,101 @@
+
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author randy sesser
+ * @copyright 2011, randy sesser
+ * @license http://www.opensource.org/licenses/mit-license The MIT License
+ * @package Instaphp
+ * @filesource
+ */
+
+namespace Instaphp\Instagram {
+
+ use Instaphp\Config;
+ use Instaphp\Request;
+ use Instaphp\Response;
+
+ /**
+ * Tags
+ * The Tags class handles all tag based API calls
+ * @package Instaphp
+ * @version 1.0
+ * @author randy sesser
+ */
+ class Tags extends InstagramBase
+ {
+
+ public function __construct($token = null)
+ {
+ parent::__construct($token);
+ $this->api_path = '/tags';
+ }
+
+ /**
+ * Gets infor about a particular tag
+ * @access public
+ * @param string $tag A tag name
+ * @param string $token An access token
+ * @return Response
+ */
+ public function Info($tag = mull)
+ {
+ if (empty($tag))
+ trigger_error("You didn't supply a tag, not sure what whill happen here...", E_USER_WARNING);
+
+ return $this->Get($this->buildUrl($tag));
+ }
+
+ /**
+ * Gets recent media tagged with $tag
+ * @access public
+ * @param string $tag A tag name
+ * @param string $token An access token
+ * @param Array $params An associative array of key/value pairs to pass to the API
+ * @return Response
+ */
+ public function Recent($tag, Array $params = array())
+ {
+ if (!empty($params))
+ $this->AddParams($params);
+
+ return $this->Get($this->buildUrl($tag . '/media/recent'));
+ }
+
+ /**
+ * Searches for media by tag
+ * @access public
+ * @param string $query
+ * @param string $token
+ * @return Response
+ */
+ public function Search($query = '')
+ {
+ $this->AddParam('q', $query);
+ return $this->Get($this->buildUrl('search'));
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/web/lib/instagram_api/instagram/users.php b/web/lib/instagram_api/instagram/users.php
new file mode 100644
index 0000000..a8ad81d
--- /dev/null
+++ b/web/lib/instagram_api/instagram/users.php
@@ -0,0 +1,274 @@
+
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author randy sesser
+ * @copyright 2011, randy sesser
+ * @license http://www.opensource.org/licenses/mit-license The MIT License
+ * @package Instaphp
+ * @filesource
+ */
+
+namespace Instaphp\Instagram {
+
+ use Instaphp\Config;
+ use Instaphp\Request;
+ use Instaphp\Response;
+
+ /**
+ * Users
+ * The Users class handles all users request to the API
+ * @package Instaphp
+ * @version 1.0
+ * @author randy sesser
+ */
+ class Users extends InstagramBase
+ {
+
+ public function __construct($token = null)
+ {
+ parent::__construct($token);
+ $this->api_path = '/users';
+ }
+
+ /**
+ * Gets the access token from an oAuth request
+ * @access public
+ * @param string $code The authorization code returned by the oAuth call
+ * @param string $scope The scope of the oAuth request
+ * @return Response
+ */
+ public function Authenticate($code, $scope = null)
+ {
+ if (!empty($code)) {
+ $this->AddParams(array(
+ 'code' => $code,
+ 'client_secret' => $this->config->Instagram->ClientSecret,
+ 'grant_type' => 'authorization_code',
+ 'redirect_uri' => $this->config->Instaphp->RedirectUri
+ ));
+
+ return $this->Post($this->config->GetOAuthTokenUri());
+ }
+ }
+
+ /**
+ * Gets info about a particular user
+ * @access public
+ * @param mixed $user_id A user ID or 'self' to get info about the currently authenticated user
+ * @return Response
+ */
+ public function Info($user_id = 'self')
+ {
+ return $this->Get($this->buildUrl($user_id));
+ }
+
+ /**
+ * Gets a users feed
+ * @access public
+ * @param string $token An access token
+ * @param Array $params An associative array of key/value pairs to pass to the API.
+ * @return Response
+ */
+ public function Feed(Array $params = array())
+ {
+ if (!empty($params))
+ $this->AddParams($params);
+
+ return $this->Get($this->buildUrl('self/feed/'));
+ }
+
+ /**
+ * Gets a user most recent media
+ * @access public
+ * @param mixed $user_id A user ID or 'self' to get info about the currently authenticated user
+ * @param Array $params An associative array of key/value pairs to pass to the API
+ * @return Response
+ */
+ public function Recent($user_id, Array $params = array())
+ {
+ if (!empty($params))
+ $this->AddParams($params);
+
+ return $this->Get($this->buildUrl($user_id . '/media/recent/'));
+ }
+
+ /**
+ * Gets media liked by the current user
+ * @access public
+ * @param Array $params An associative array of key/value pairs to pass to the API
+ * @return Response
+ */
+ public function Liked(Array $params = array())
+ {
+ if (!empty($params))
+ $this->AddParams($params);
+ return $this->Get($this->buildUrl('self/media/liked/'));
+ }
+
+ /**
+ * Search for a user by username
+ * @access public
+ * @param string $query A username
+ * @return Response
+ */
+ public function Find($query = '')
+ {
+ $this->AddParam('q', $query);
+ return $this->Get($this->buildUrl('search'));
+ }
+
+ /**
+ * Gets followers of a particular user
+ * @access public
+ * @param mixed $user_id A user ID or 'self' to get info about the currently authenticated user
+ * @param Array $params Additional params to pass to the API
+ * @return Response
+ */
+ public function Following($user_id, Array $params = array())
+ {
+ if (!empty($params))
+ $this->AddParams($params);
+
+ return $this->Get($this->buildUrl($user_id . '/follows'));
+ }
+
+ /**
+ * Gets a user's followers
+ * @access public
+ * @param mixed $user_id A user ID or 'self' to get info about the currently authenticated user
+ * @param Array $params Additional params to pass to the API
+ * @return Response
+ */
+ public function Followers($user_id, Array $params = array())
+ {
+ if (!empty($params))
+ $this->AddParams($params);
+
+ return $this->Get($this->buildUrl($user_id . '/followed-by'));
+ }
+
+ /**
+ * Gets requests for follows for a particular user
+ * @access public
+ * @param mixed $user_id A user ID or 'self' to get info about the currently authenticated user
+ * @return Response
+ */
+ public function Requests($user_id)
+ {
+
+ }
+
+ /**
+ * Gets the relationship of a user based on the currently authenticated user
+ * @access public
+ * @param mixed $user_id A user ID or 'self' to get info about the currently authenticated user
+ * @return Response
+ */
+ public function Relationship($user_id)
+ {
+ return $this->Get($this->buildUrl($user_id . '/relationship'));
+ }
+
+ /**
+ * Sets a relationship between a particular user and the currently authenticated user
+ * @access public
+ * @param int $user_id A user ID
+ * @param Array $token An associative array of key/value pairs to pass to the API
+ * @return Response
+ */
+ protected function SetRelationship($user_id, $action)
+ {
+ $this->AddParam('action', $action);
+ return $this->Post($this->buildUrl($user_id . '/relationship'));
+ }
+
+ /**
+ * Follow a user...
+ * @access public
+ * @param int $user_id A user ID
+ * @return Response
+ */
+ public function Follow($user_id)
+ {
+ return $this->SetRelationship($user_id, 'follow');
+ }
+
+ /**
+ * Unfollow a user...
+ * @access public
+ * @param int $user_id A user ID
+ * @return Response
+ */
+ public function Unfollow($user_id)
+ {
+ return $this->SetRelationship($user_id, 'unfollow');
+ }
+
+ /**
+ * Block a user...
+ * @access public
+ * @param int $user_id A user ID
+ * @return Response
+ */
+ public function Block($user_id)
+ {
+ return $this->SetRelationship($user_id, 'block');
+ }
+
+ /**
+ * Unblock a user...
+ * @access public
+ * @param int $user_id A user ID
+ * @return Response
+ */
+ public function Unblock($user_id)
+ {
+ $this->SetRelationship($user_id, 'unblock');
+ }
+
+ /**
+ * Approve a user request...
+ * @access public
+ * @param int $user_id A user ID
+ * @return Response
+ */
+ public function Approve($user_id)
+ {
+ $this->SetRelationship($user_id, 'approve');
+ }
+
+ /**
+ * Deny a user request...
+ * @access public
+ * @param int $user_id A user ID
+ * @return Response
+ */
+ public function Deny($user_id)
+ {
+ $this->SetRelationship($user_id, 'deny');
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/web/lib/instagram_api/instaphp.php b/web/lib/instagram_api/instaphp.php
new file mode 100644
index 0000000..d81df65
--- /dev/null
+++ b/web/lib/instagram_api/instaphp.php
@@ -0,0 +1,109 @@
+
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author randy sesser
+ * @copyright 2011, randy sesser
+ * @license http://www.opensource.org/licenses/mit-license The MIT License
+ * @package Instaphp
+ * @filesource
+ */
+
+namespace Instaphp {
+
+ $dirname = dirname(__FILE__).'/';
+
+ require_once( $dirname. 'config.php');
+ require_once( $dirname. 'webrequest.php');
+ require_once( $dirname. 'request.php');
+ require_once( $dirname. 'response.php');
+ require_once( $dirname. 'instagram/instagrambase.php');
+ require_once( $dirname. 'instagram/users.php');
+ require_once( $dirname. 'instagram/media.php');
+ require_once( $dirname. 'instagram/tags.php');
+ require_once( $dirname. 'instagram/locations.php');
+
+ /**
+ * A simple base class used to instantiate the various other API classes
+ * @package Instaphp
+ * @version 1.0
+ * @author randy sesser
+ */
+ class Instaphp
+ {
+
+ /**
+ * @var Users
+ * @access public
+ */
+ public $Users = null;
+ /**
+ * @var Media
+ * @access public
+ */
+ public $Media = null;
+ /**
+ * @var Tags
+ * @access public
+ */
+ public $Tags = null;
+ /**
+ * @var Locations
+ */
+ public $Locations = null;
+
+ /**
+ * Contains the last API url called
+ *
+ * @var string
+ **/
+ public $url = null;
+
+ private static $instance = null;
+ /**
+ * The constructor constructs, but only for itself
+ */
+ final private function __construct($token = null)
+ {
+ $this->Users = new Instagram\Users($token);
+ $this->Media = new Instagram\Media($token);
+ $this->Tags = new Instagram\Tags($token);
+ $this->Locations = new Instagram\Locations($token);
+ }
+
+ /**
+ * I AM SINGLETON
+ * We don't need to go instantiating all these objects more than once here
+ * @return Instaphp
+ */
+ public static function Instance($token = null)
+ {
+ if (self::$instance == null || !empty($token)) {
+ self::$instance = new self($token);
+ }
+ return self::$instance;
+ }
+ }
+
+}
diff --git a/web/lib/instagram_api/instaphpexception.php b/web/lib/instagram_api/instaphpexception.php
new file mode 100644
index 0000000..8620fd4
--- /dev/null
+++ b/web/lib/instagram_api/instaphpexception.php
@@ -0,0 +1,18 @@
+
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author randy sesser
+ * @copyright 2011, randy sesser
+ * @license http://www.opensource.org/licenses/mit-license The MIT License
+ * @package Instaphp
+ * @filesource
+ */
+
+namespace Instaphp {
+
+ use Instaphp\Config;
+ use Instaphp\Cache;
+ use Instaphp\WebRequest;
+ /**
+ * Request
+ * The Request class performs simple curl requests to a URL optionally passing
+ * parameters on the querystring. Currently, it supports GET,POST and DELETE requests.
+ * @package Instaphp
+ * @version 1.0
+ * @author randy sesser
+ */
+ class Request
+ {
+
+ /**
+ * Associative array of key/value pairs to pass to the Instagram API
+ * @var Array
+ * @access public
+ */
+ public $parameters = array();
+ /**
+ * The URL in which to make the request
+ * @var String
+ * @access public
+ */
+ public $url = null;
+ /**
+ * A var to store whether or not to use curl
+ * @var boolean
+ * @access private
+ */
+ private $useCurl = false;
+
+ /**
+ *
+ * @var iCache Cache object used for caching
+ * @access private
+ */
+ private $_cache = null;
+
+ /**
+ * The constructor contructs
+ * @param string $url A URL in which to create a new request (optional)
+ * @param Array $params An associated array of key/value pairs to pass to said URL (optional)
+ */
+ public function __construct($url = null, $params = array())
+ {
+ $this->useCurl = self::HasCurl();
+ $this->parameters = $params;
+ $this->url = $url;
+
+/*
+ $cacheConfig = Config::Instance()->GetSection("Instaphp/Cache");
+ if (!empty($cacheConfig) && count($cacheConfig) > 0) {
+ $cacheConfig = $cacheConfig[0];
+ if ($cacheConfig["Enabled"]) {
+ $engine = (string)$cacheConfig["Engine"];
+ $this->_cache = Cache\Cache::Instance($engine);
+ // $method = new \ReflectionMethod("Instaphp\\Cache\\".$engine, 'Instance');
+ // $this->_cache = $method->invoke(null, null);
+ // $this->_cache = Cache\File::Instance();
+ }
+
+ }
+*/
+ }
+
+
+ /**
+ * Makes a GET request
+ * @param string $url A URL in which to make a GET request
+ * @param Array $params An associative array of key/value pairs to pass to said URL
+ * @return Request
+ */
+ public function Get($url = null, $params = array())
+ {
+ if (null !== $url)
+ $this->url = $url;
+
+ if (!empty($params))
+ $this->parameters = $params;
+ $query = '';
+ foreach ($this->parameters as $k => $v)
+ $query .= ((strlen ($query) == 0) ? '?' : '&') . sprintf('%s=%s', $k, $v);
+
+ if (null !== $this->_cache) {
+ $key = sha1($url.$query);
+
+ if (false === ($response = $this->_cache->Get($key))) {
+ $response = $this->GetResponse();
+ if (empty ($response->error)) {
+ $this->_cache->Set($key, $response);
+ }
+ }
+ } else {
+ $response = $this->GetResponse();
+ }
+
+ $this->response = $response;
+ return $this;
+ }
+
+ /**
+ * Makes a POST request
+ * @param string $url A URL in which to make a POST request
+ * @param Array $params An associative array of key/value pairs to pass to said URL
+ * @return Request
+ */
+ public function Post($url = null, $params = array())
+ {
+ if (null !== $url)
+ $this->url = $url;
+
+ if (!empty($params))
+ $this->parameters = $params;
+
+ $this->response = $this->GetResponse('POST');
+ return $this;
+ }
+
+ /**
+ * Makes a PUT request (currently unused)
+ * @param string $url A URL in which to make a PUT request
+ * @param Array $params An associative array of key/value pairs to pass to said URL
+ * @return void
+ */
+ public function Put($url = null, $params = array())
+ {
+
+ }
+
+ /**
+ * Makes a DELETE request
+ * @param string $url A URL in which to make a DELETE request
+ * @param Array $params An associative array of key/value pairs to pass to said URL
+ * @return Request
+ */
+ public function Delete($url = null, $params = array())
+ {
+ if (null !== $url)
+ $this->url = $url;
+
+ if (!empty($params))
+ $this->parameters = $params;
+
+ $this->response = $this->GetResponse('DELETE');
+ return $this;
+ }
+
+ /**
+ * Makes a request
+ * @param string $url A URL in which to make a GET request
+ * @param Array $params An associative array of key/value pairs to pass to said URL
+ * @access private
+ * @return Response
+ */
+ private function GetResponse($method = 'GET')
+ {
+ //-- since there's no option to use anything other curl, this check is kinda useless
+ //-- I had high hopes with this one using sockets and whatnot, but alas, time is of
+ //-- the essence... in internet time
+ if ($this->useCurl) {
+
+ $response = new Response;
+
+ $http = WebRequest::Instance();
+ $res = $http->Create($this->url, $method, $this->parameters);
+
+ if ($res instanceof Error)
+ return $res;
+
+ $response->info = $res->Info;
+ $response->json = $res->Content;
+ $response = Response::Create($this, $response);
+ return $response;
+ }
+ }
+
+ /**
+ * Checks to see if cURL extension is available
+ * @access private
+ * @return boolean
+ */
+ private static function HasCurl()
+ {
+ return function_exists('curl_init');
+ }
+
+ /**
+ * Determines whether or not curl will follow redirects over SSL
+ * See the constructor for details, but there are cases in which
+ * if curl can't verify the certificate of an SSL request, AND
+ * PHP is in safe_mode OR there are open_basedir restrictions, it will
+ * not follow a redirect. There's a fix for this that involves
+ * parsing all the response headers from a request and detecting
+ * a Location header, but that's kind of a hack as it bypasses the
+ * whole point of SSL. This method left for posterity. Or something...
+ *
+ * @return boolean
+ * @access private
+ **/
+ private function WillFollowRedirects()
+ {
+ $open_basedir = ini_get('open_basedir');
+ $safe_mode = strtolower(ini_get('safe_mode'));
+ if (empty($open_basedir) && $safe_mode == 'off') {
+ return true;
+ }
+ return false;
+ }
+
+ }
+}
diff --git a/web/lib/instagram_api/response.php b/web/lib/instagram_api/response.php
new file mode 100644
index 0000000..d4ed79e
--- /dev/null
+++ b/web/lib/instagram_api/response.php
@@ -0,0 +1,279 @@
+
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author randy sesser
+ * @copyright 2011, randy sesser
+ * @license http://www.opensource.org/licenses/mit-license The MIT License
+ * @package Instaphp
+ * @filesource
+ */
+
+namespace Instaphp {
+ /**
+ * The Response object.
+ * This is the object passed back to the caller of this framework. It mimcs
+ * Instagram's JSON objects returned from most (if not all) of its current
+ * endpoints. Not all properties will be populated, so isset() should be used
+ * when dealing with a response object's properties
+ * @package Instaphp
+ * @version 1.0
+ * @author randy sesser
+ */
+ class Response
+ {
+ /**
+ * Technical information about the http response
+ *
+ * @var array
+ * @access public
+ */
+ public $info;
+ /**
+ * The meta "object" (contains a status code. 200 when successful)
+ * @var object
+ * @access public
+ */
+ public $meta = null;
+ /**
+ * The data "object" contains everything. Too much to list here.
+ * See {@link https://api.instagram.com/developer/ Instagram Developer API}
+ * @var object
+ * @access public
+ */
+ public $data = null;
+ /**
+ * The pagination "object" is not your typical pagination
+ * @var object
+ * @access public
+ */
+ public $pagination = null;
+ /**
+ * If an error occurred, this will be populated. Check here first.
+ *
+ * if (!empty(\$response->error)) {
+ * echo \$response->error->message;
+ * }
+ *
+ * @var Error
+ * @access public
+ */
+ public $error = null;
+ /**
+ * When authenticating, this is populated with the access token and basic
+ * user info returned from the API
+ * @var object
+ * @access public
+ */
+ public $auth = null;
+ /**
+ * For embeded calls
+ *
+ * @var object
+ * @access public
+ **/
+ public $embed = null;
+ /**
+ * This is the raw JSON response returned from the API. Usefull if
+ * you just want a "passthrough" situation or perhaps you want to embed
+ * the JSON string in the page and parse it with JavaScript.
+ *
+ * var response = JSON.parse('json ?>');
+ *
+ * @var string
+ * @access public
+ */
+ public $json = '';
+
+ public function __construct()
+ {
+
+ }
+
+ /**
+ * A convenience method to parse the response text and build a Response object
+ * @access public
+ * @static
+ * @param string $responseText The response from the API call
+ * @param string $url The url used to generate the Response object
+ * @return Response
+ */
+ public static function Create(Request $request, Response $response)
+ {
+ $obj = json_decode($response->json);
+
+ //-- for embeded calls, just return the embeded object
+ if (isset($obj->{'provider_url'}) && !empty($obj->{'provider_url'})) {
+ $response->embed = $obj;
+ return $response;
+ }
+
+ if (empty($obj)) {
+ $error = new Error;
+ $error->type = 'cURLResponseError';
+ $error->code = $response->info['http_code'];
+ $error->url = $response->info['url'];
+ switch ($error->code)
+ {
+ case 505:
+ $error->message = 'HTTP version not supported? Weird.';
+ break;
+ case 504:
+ $error->message = 'Gateway timeout. Sorry.';
+ break;
+ case 503:
+ $error->message = 'The API is currently unavailable';
+ break;
+ case 502:
+ $error->message = 'Baaaaaaaaad gateway!';
+ break;
+ case 501:
+ $error->message = 'Sorry, not implemented... YET.';
+ break;
+ case 500:
+ $error->message = 'Whoops! API just barfed on your new shoes.';
+ break;
+ case 405:
+ $error->message = 'Method not allowed.';
+ break;
+ case 404:
+ $error->message = 'Received a 404 from the API';
+ break;
+ case 403:
+ $error->message = 'The API says you are forbidden';
+ break;
+ case 402:
+ $error->message = 'The API claims you own them money.';
+ break;
+ case 401:
+ $error->message = 'The API says you are unauthorized.';
+ break;
+ case 400:
+ $error->message = 'POBR... Plain Old Bad Request.';
+ break;
+ default:
+ $error->message = 'Unknown error ocurred making this request';
+ break;
+ }
+ $response->error = $error;
+ }
+
+ if (isset($obj->{'error_message'})) {
+ $response->error = new Error($obj->{'error_type'}, $obj->{'code'}, $obj->{'error_message'}, $response->info['url']);
+ }
+
+ if (isset($obj->{'access_token'})) {
+ $response->auth->access_token = $obj->{'access_token'};
+ $response->auth->user = $obj->{'user'};
+ }
+
+ if (isset($obj->{'meta'}))
+ $response->meta = $obj->{'meta'};
+
+ if (isset($obj->{'meta'}) && $obj->{'meta'}->code !== 200) {
+ $response->error = new Error($response->meta->error_type, $response->meta->code, $response->meta->error_message, $response->info['url']);
+ $query = '';
+
+ }
+
+ if (isset($obj->{'data'}))
+ $response->data = $obj->{'data'};
+
+ if (isset($obj->{'pagination'}))
+ $response->pagination = $obj->{'pagination'};
+
+ return $response;
+ }
+
+ private static function fixNonUtf8Chars($data)
+ {
+ $aux = str_split($data);
+ foreach($aux as $a) {
+ $a1 = urlencode($a);
+ $aa = explode("%", $a1);
+
+ foreach($aa as $v)
+ if($v!="")
+ if(hexdec($v)>127)
+ $data = str_replace($a,"".hexdec($v).";",$data);
+
+ }
+
+ return $data;
+ }
+ }
+
+ /**
+ * Error Object
+ *
+ *
+ * @package Instaphp
+ * @version 1.0
+ * @author randy sesser
+ */
+ class Error
+ {
+ /**
+ * Error Type
+ * @var string
+ * @access public
+ */
+ public $type = null;
+ /**
+ * Error Code
+ * @var int
+ * @access public
+ */
+ public $code = null;
+ /**
+ * Error Message
+ * @var string
+ * @access public
+ */
+ public $message = null;
+ /**
+ * The url associated with this error
+ *
+ * @var string
+ * @access public
+ **/
+ public $url = null;
+
+ /**
+ * The constructor constructs
+ * @param string $type The error type
+ * @param int $code The error code
+ * @param string $message The error message
+ * @return Error
+ * @access public
+ */
+ public function __construct($type = null, $code = null, $message = null, $url = null)
+ {
+ $this->type = $type;
+ $this->code = $code;
+ $this->message = $message;
+ $this->url = $url;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/web/lib/instagram_api/webrequest.php b/web/lib/instagram_api/webrequest.php
new file mode 100644
index 0000000..4dce0c7
--- /dev/null
+++ b/web/lib/instagram_api/webrequest.php
@@ -0,0 +1,284 @@
+
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author randy sesser
+ * @copyright 2011, randy sesser
+ * @license http://www.opensource.org/licenses/mit-license The MIT License
+ * @package Instaphp
+ * @filesource
+ */
+namespace Instaphp
+{
+ class WebRequest
+ {
+ /**
+ *
+ * @var resource A cURL multi handle resource
+ * @access private
+ */
+ private $mh = null;
+
+ /**
+ *
+ * @var array Array of active requests
+ * @access private
+ */
+ private $_requests;
+
+ /**
+ *
+ * @var array Array of stored responses
+ * @access private
+ */
+ private $_responses;
+ /**
+ *
+ * @var array Array of common cURL options
+ * @access private
+ */
+ private $_options = array(
+ CURLOPT_FOLLOWLOCATION => true,
+ CURLOPT_HEADER => false,
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_CONNECTTIMEOUT => 2,
+ CURLOPT_TIMEOUT => 10,
+ CURLOPT_ENCODING => ''
+ );
+
+ /**
+ *
+ * @var WebRequest An instance of WebRequest (aka Mr. Singleton)
+ * @access private
+ */
+ static $_instance = null;
+
+ /**
+ * Constructor is private final. Can only be instantiated via WebRequest::Instance()
+ * @access private
+ * @final
+ */
+ private final function __construct()
+ {
+ $this->mh = curl_multi_init();
+
+ if (isset(Config::Instance()->Endpoint['timeout']))
+ $this->_options[CURLOPT_TIMEOUT] = Config::Instance()->Endpoint['timeout'];
+
+ $this->_options[CURLOPT_USERAGENT] = 'Instaphp/v' . INSTAPHP_VERSION;
+
+ //-- this is an interesting hack to make curl+ssl+windows follow redirects
+ //-- without skipping verification. For some reason, the version of libcurl/curl
+ //-- included with ZendServer CE doesn't use the systems CA bundle, so, we specify
+ //-- the path to the cert here (via config setting)
+ if (isset(Config::Instance()->Instaphp->CACertBundlePath) && !empty(Config::Instance()->Instaphp->CACertBundlePath)) {
+ $this->_options[CURLOPT_SSL_VERIFYPEER] = true;
+ $this->_options[CURLOPT_SSL_VERIFYHOST] = 2;
+ $this->_options[CURLOPT_SSLVERSION] = 3;
+ $this->_options[CURLOPT_CAINFO] = Config::Instance()->Instaphp->CACertBundlePath;
+ }
+
+ $this->_options[CURLOPT_HTTPHEADER] = array(
+ "Connection: keep-alive",
+ "Keep-Alive: 300",
+ "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7",
+ "Accept-Language: en-us,en;q=0.5"
+ );
+
+ $this->_requests = array();
+ $this->_responses = array();
+ }
+
+ /**
+ * Instantiates a new WebRequest if one does not already exist
+ *
+ * @return WebRequest A single instance of WebRequest
+ * @access public
+ * @static
+ */
+ public static function Instance()
+ {
+ if (null == static::$_instance)
+ static::$_instance = new self();
+ return static::$_instance;
+ }
+
+ /**
+ * Convenience method for http GET requests
+ *
+ * @param string $url The url to Get
+ * @param array $parameters An array of key/value pairs to pass
+ * @return WebRequestManager A WebRequestManager to manage the current request
+ * @access public
+ */
+ public function Get($url, $parameters = array())
+ {
+ return $this->Create($url, "GET", $parameters);
+ }
+
+ /**
+ * Convenience method for http POST requests
+ *
+ * @param string $url The url to POST
+ * @param array $parameters An array of key/value pairs to pass
+ * @return WebRequestManager A WebRequestManager to manage the current request
+ * @access public
+ */
+ public function Post($url, $parameters = array())
+ {
+ return $this->Create($url, "POST", $parameters);
+ }
+
+ /**
+ * Convenience method for http DELETE requests
+ *
+ * @param string $url The url to DELETE
+ * @param array $parameters An array of key/value pairs to pass
+ * @return WebRequestManager A WebRequestManager to manage the current request
+ * @access public
+ */
+ public function Delete($url, $parameters = array())
+ {
+ return $this->Create($url, "DELETE", $parameters);
+ }
+
+ /**
+ * Creates a new cURL reuest and adds to the request queue for processing
+ * @param string $url The url in which to make the request
+ * @param string $method The method used to make the request [GET|POST|DELETE]
+ * @param array $parameters Array of key/value pairs to pass to the request
+ * @return mixed A WebRequestManager to manage the current request on success, Error on failure
+ * @access public
+ */
+ public function Create($url, $method = 'GET', $parameters = array())
+ {
+ $ch = curl_init();
+ $key= (string)$ch;
+ $query = '';
+ $res = null;
+
+ $options = $this->_options;
+
+ foreach ($parameters as $k => $v)
+ $query .= ((strlen ($query) == 0) ? "":"&") . sprintf('%s=%s', $k, urlencode($v));
+
+ switch (strtolower($method))
+ {
+ case 'post':
+ $options[CURLOPT_POST] = true;
+ $options[CURLOPT_POSTFIELDS] = $query;
+ break;
+ case 'delete':
+ $options[CURLOPT_CUSTOMREQUEST] = 'DELETE';
+ $url .= '?' . $query;
+ break;
+ default:
+ $url .= '?' . $query;
+ break;
+ }
+
+ $options[CURLOPT_URL] = $url;
+ curl_setopt_array($ch, $options);
+
+ $this->_requests[$key] = $ch;
+
+ $res = curl_multi_add_handle($this->mh, $this->_requests[$key]);
+ if ($res == CURLM_OK) {
+ curl_multi_exec($this->mh, $active);
+ return new WebRequestManager($key);
+ }
+ return new Error('cURLError', curl_error($ch), curl_errno($ch), $options[CURLOPT_URL]);
+ }
+
+ /**
+ *
+ * @param string $key The key used to get the current request from the queue
+ * @return WebResponse A WebResponse for the $key
+ * @access public
+ */
+ public function GetResponse($key = null)
+ {
+ if (isset($this->_responses[$key]))
+ return $this->_responses[$key];
+
+ $running = null;
+
+ do {
+ $res = curl_multi_exec($this->mh, $current);
+ if (null !== $running && $current != $running) {
+ $this->store();
+
+ if (isset($this->_responses[$key]))
+ return $this->_responses[$key];
+
+ }
+ $running = $current;
+ } while ($current > 0);
+
+ return false;
+ }
+
+ /**
+ * Runs through the request queue and processes completed requests
+ * @access private
+ */
+ private function store()
+ {
+ while ($finished = curl_multi_info_read($this->mh, $messages)) {
+ $key = (string)$finished["handle"];
+ $this->_responses[$key] = new WebResponse(curl_multi_getcontent($finished["handle"]), curl_getinfo($finished["handle"]));
+ curl_multi_remove_handle($this->mh, $finished["handle"]);
+ }
+ }
+ }
+
+ class WebRequestManager
+ {
+ private $key;
+ private $request;
+
+ public function __construct($key)
+ {
+ $this->key = $key;
+ $this->request = WebRequest::Instance();
+ }
+
+ public function __get($name)
+ {
+ $response = $this->request->GetResponse($this->key);
+ return $response->{$name};
+ }
+ }
+
+ class WebResponse
+ {
+ public $Content;
+ public $Info;
+
+ public function __construct($content = null, $info = null)
+ {
+ $this->Content = $content;
+ $this->Info = $info;
+ }
+ }
+}
\ No newline at end of file
diff --git a/web/module/imagehosting/ImageDO.php b/web/module/imagehosting/ImageDO.php
new file mode 100644
index 0000000..dda007f
--- /dev/null
+++ b/web/module/imagehosting/ImageDO.php
@@ -0,0 +1,96 @@
+
+ */
+class ImageDO extends SimpleImage implements Image {
+
+ // -----------------------------------------------
+ // Private properties
+ // -----------------------------------------------
+
+ /**
+ * Image table used to manage table with image data.
+ *
+ * @var ImageTable
+ */
+ private $imageTable;
+
+ /**
+ * Image's user.
+ *
+ * @var string
+ */
+ private $user;
+
+ // -----------------------------------------------
+ // Constructor
+ // -----------------------------------------------
+
+ /**
+ * @param ImageTable $imageTable - ImageTable object used to perform operations with image table
+ * @param $id - id of the image
+ * @param $url - image's url
+ * @param $name - image's name
+ * @param string|null $user - image's user
+ */
+ public function __construct(ImageTable $imageTable, $id, $url, $name, $user = null) {
+ parent::__construct($id, $url, $name);
+ $this->imageTable = $imageTable;
+ $this->user = $user;
+ $imageTable->insertOrUpdate($this->getId(), $this->getTableValues());
+ }
+
+ // -----------------------------------------------
+ // Public methods
+ // -----------------------------------------------
+
+ /**
+ * Sets the user of the image.
+ *
+ * @param $user - user's name
+ */
+ public function setUser($user) {
+ $this->user = $user;
+ }
+
+ // -----------------------------------------------
+ // Overridden methods (from Image)
+ // -----------------------------------------------
+
+ public function setDescription($description) {
+ parent::setDescription($description);
+ $this->imageTable->updateDescription($this->getId(), $this->getDescription());
+ }
+
+ public function removeDescription() {
+ parent::removeDescription();
+ $this->imageTable->updateDescription($this->getId(), $this->getDescription());
+ }
+
+ public function setFavorite($is) {
+ $this->imageTable->updateFavorite($this->getId(), $this->isFavorite());
+ }
+
+ // -----------------------------------------------
+ // Private methods
+ // -----------------------------------------------
+
+ /**
+ * Gets the values to insert into the table.
+ *
+ * @return array
+ */
+ private function getTableValues() {
+ return array( $this->getId(),
+ $this->user,
+ $this->getUrl(),
+ $this->getName(),
+ $this->getDescription(),
+ $this->isFavorite());
+ }
+
+}
\ No newline at end of file
diff --git a/web/module/imagehosting/ImageHostingController.php b/web/module/imagehosting/ImageHostingController.php
new file mode 100644
index 0000000..68f2428
--- /dev/null
+++ b/web/module/imagehosting/ImageHostingController.php
@@ -0,0 +1,207 @@
+
+ */
+class ImageHostingController {
+
+ // -----------------------------------------------
+ // Private properties
+ // -----------------------------------------------
+
+ /**
+ * Concrete external service provides access to the external image services.
+ *
+ * @var ExternalService
+ */
+ private $service;
+
+ /**
+ * Service factory helps to create specific external service.
+ *
+ * @var ExternalServiceFactory
+ */
+ private $serviceFactory;
+
+ /**
+ * Database used to store image data.
+ *
+ * @var Database
+ */
+ private $database;
+
+ /**
+ * Image table used to manage table with image data.
+ *
+ * @var ImageTable
+ */
+ private $imageTable;
+
+ /**
+ * User with its own session.
+ *
+ * @var User
+ */
+ private $user;
+
+ // -----------------------------------------------
+ // Constructor
+ // -----------------------------------------------
+
+ /**
+ * @param $dbServer - mysql server address
+ * @param $dbUsername - mysql server username
+ * @param $dbPassword - mysql server password
+ * @param $dbName - database name used to store image hosting service data
+ */
+ public function __construct($dbServer, $dbUsername, $dbPassword, $dbName) {
+ $this->serviceFactory = ExternalServiceFactory::getInstance();
+ $this->database = new MysqlDatabase($dbServer, $dbUsername, $dbPassword, $dbName);
+ $this->imageTable = new ImageTable($this->database);
+ $this->user = new User();
+ }
+
+ // -----------------------------------------------
+ // Public methods
+ // -----------------------------------------------
+
+ /**
+ * Outputs all previously generated images, except favorite images.
+ */
+ public function showGeneratedImages() {
+ $list = $this->imageTable->getListByUser($this->user->getName());
+ $this->printImageTable($list);
+ }
+
+ /**
+ * Shows images that were tagged as "favorite" images.
+ */
+ public function showFavoriteImages() {
+ $list = $this->imageTable->getFavoriteList($this->user->getName());
+ $this->printImageTable($list);
+ }
+
+ /**
+ * Generates images from specific service.
+ *
+ * @param $serviceName - service images from will be generated
+ */
+ public function generateImages($serviceName) {
+
+ $this->removeNonFavoriteImages();
+
+ if ($serviceName == 'flikr') {
+ $this->service = $this->serviceFactory->createFlikrService();
+ } else if ($serviceName == 'instagram') {
+ $this->service = $this->serviceFactory->createInstagramService();
+ }
+
+ $images = $this->service->loadMetadata();
+ $dbImages = array();
+
+ foreach ($images as $image) {
+ $i = new ImageDO( $this->imageTable,
+ $image->getId(),
+ $image->getUrl(),
+ $image->getName(),
+ $this->user->getName());
+ $i->setDescription("");
+ $dbImages[] = $i->toArray();
+ }
+
+ $this->printImages($dbImages);
+ }
+
+ /**
+ * Sets image with specific id as favorite.
+ *
+ * @param $id - id of the image in the database
+ */
+ public function addFavoriteImage($id) {
+ $this->imageTable->updateFavorite($id, true);
+ }
+
+ /**
+ * Removes favorite status of the image.
+ *
+ * @param $id - id of the image in the database
+ */
+ public function removeFavoriteImage($id) {
+ $this->imageTable->delete($id);
+ //$this->imageTable->updateFavorite($id, false);
+ }
+
+ /**
+ * Sets the description of the image.
+ *
+ * @param $id - id of the image in the database
+ * @param $description - new image description
+ */
+ public function setImageDescription($id, $description) {
+ $this->imageTable->updateDescription($id, $description);
+ }
+
+ /**
+ * Removes image's description.
+ *
+ * @param $id - id of the image in the database
+ */
+ public function removeImageDescription($id) {
+ $this->imageTable->updateDescription($id, "");
+ }
+
+ /**
+ * Removes all generated images (including favorite) of the current user.
+ */
+ public function removeImages() {
+ $this->imageTable->deleteByUser($this->user->getName());
+ }
+
+ // -----------------------------------------------
+ // Private methods
+ // -----------------------------------------------
+
+ /**
+ * Removes all random images (non favorite) of the current user.
+ */
+ private function removeNonFavoriteImages() {
+ $this->imageTable->deleteWithFavoriteStatus($this->user->getName(), false);
+ }
+
+ /**
+ * Outputs image list that has been retrieved from the images table.
+ *
+ * @param $list
+ */
+ private function printImageTable($list) {
+
+ if ($list == null || count($list) == 0)
+ return;
+
+
+ $images = array();
+ foreach ($list as $row) {
+ $i = new SimpleImage( $row[ImageTable::FIELD_ID],
+ $row[ImageTable::FIELD_URL],
+ $row[ImageTable::FIELD_NAME]);
+ $i->setDescription($row[ImageTable::FIELD_DESCRIPTION]);
+ $i->setFavorite($row[ImageTable::FIELD_FAVORITE]);
+ $images[] = $i->toArray();
+ }
+
+ $this->printImages($images);
+ }
+
+ /**
+ * Prints the array to the output stream in json format.
+ *
+ * @param array $images
+ */
+ private function printImages(array $images) {
+ if ($images != null && count($images) > 0)
+ echo json_encode($images);
+ }
+
+}
\ No newline at end of file
diff --git a/web/module/imagehosting/ImageTable.php b/web/module/imagehosting/ImageTable.php
new file mode 100644
index 0000000..5025b2a
--- /dev/null
+++ b/web/module/imagehosting/ImageTable.php
@@ -0,0 +1,193 @@
+
+ */
+class ImageTable extends SimpleTable {
+
+ // -----------------------------------------------
+ // Constants
+ // -----------------------------------------------
+
+ /**
+ * Table's name.
+ */
+ const TABLE_NAME = 'images';
+
+ /**
+ * Table field. Image's id.
+ */
+ const FIELD_ID = 'id';
+
+ /**
+ * Table field. Image's user.
+ */
+ const FIELD_USER = 'user';
+
+ /**
+ * Table field. Image's url.
+ */
+ const FIELD_URL = 'url';
+
+ /**
+ * Table field. Image's name.
+ */
+ const FIELD_NAME = 'name';
+
+ /**
+ * Table field. Image's description.
+ */
+ const FIELD_DESCRIPTION = 'description';
+
+ /**
+ * Table field. Indicates if image is favorite or not.
+ */
+ const FIELD_FAVORITE = 'isFavorite';
+
+ // -----------------------------------------------
+ // Constructor
+ // -----------------------------------------------
+
+ /**
+ * @param Database $database - database used to work with this table
+ */
+ public function __construct(Database $database) {
+ parent::__construct(self::TABLE_NAME, $database);
+ }
+
+ // -----------------------------------------------
+ // Public methods
+ // -----------------------------------------------
+
+ /**
+ * Gets the list of the rows only with specific user name.
+ *
+ * @param $user - the user name
+ * @return null|array
+ */
+ public function getListByUser($user) {
+ $condition = $this->getUserCondition($user) . " AND `" . self::FIELD_FAVORITE . "`='0'";
+ return $this->getDatabase()->select(self::TABLE_NAME,
+ null,
+ $condition,
+ $this->getTablePrimaryRow(),
+ null);
+ }
+
+ /**
+ * Gets the list of favorite images of the specific user.
+ *
+ * @param $user - the user name
+ * @return null|array
+ */
+ public function getFavoriteList($user) {
+ $condition = $this->getUserCondition($user) . " AND `" . self::FIELD_FAVORITE . "`='1'";
+ return $this->getDatabase()->select(self::TABLE_NAME,
+ null,
+ $condition,
+ $this->getTablePrimaryRow(),
+ null);
+ }
+
+ /**
+ * Updates description of the specific image.
+ *
+ * @param $id - id of the image in the database
+ * @param $description - new image's description
+ * @return bool
+ */
+ public function updateDescription($id, $description) {
+ // TODO: so rough. change.
+ $description = htmlspecialchars(mysql_real_escape_string($description));
+ return $this->getDatabase()->update(self::TABLE_NAME,
+ array(self::FIELD_DESCRIPTION),
+ array($description),
+ $this->getPrimaryCondition($id));
+ }
+
+ /**
+ * Deletes all images binded to specific user.
+ *
+ * @param $user - user which images will be deleted
+ * @return bool
+ */
+ public function deleteByUser($user) {
+ return $this->getDatabase()->delete(self::TABLE_NAME, "`" . self::FIELD_USER . "`='$user'");
+ }
+
+ /**
+ * Deletes all rows with specific favorite status.
+ *
+ * @param $user - user which images will be deleted
+ * @param $favoriteStatus - with this favorite status data will be removed
+ * @return bool
+ */
+ public function deleteWithFavoriteStatus($user, $favoriteStatus) {
+ return $this->getDatabase()->delete(self::TABLE_NAME, "`" . self::FIELD_USER . "`='$user' AND "
+ . self::FIELD_FAVORITE . "='" . ($favoriteStatus ? '1' : '0') . "'");
+ }
+
+ /**
+ * Updates image status - sets its status to favorite or not.
+ *
+ * @param $id - id of the image in the database
+ * @param $isFavorite - set the image favorite or not favorite
+ * @return bool
+ */
+ public function updateFavorite($id, $isFavorite) {
+ return $this->getDatabase()->update(self::TABLE_NAME,
+ array(self::FIELD_FAVORITE),
+ array($isFavorite ? '1' : '0'),
+ $this->getPrimaryCondition($id));
+ }
+
+ // -----------------------------------------------
+ // Protected methods
+ // -----------------------------------------------
+
+ protected function getPrimaryCondition($key) {
+ // TODO: so rough. change.
+ $key = mysql_real_escape_string($key);
+ return "`" . self::FIELD_ID . "`='" . $key . "'";
+ }
+
+ protected function getTableRows() {
+ return array( self::FIELD_ID,
+ self::FIELD_USER,
+ self::FIELD_URL,
+ self::FIELD_NAME,
+ self::FIELD_DESCRIPTION,
+ self::FIELD_FAVORITE
+ );
+ }
+
+ protected function getTableRowTypes() {
+ return array( 'VARCHAR(25)',
+ 'VARCHAR(255)',
+ 'VARCHAR(255)',
+ 'VARCHAR(100)',
+ 'VARCHAR(500)',
+ 'BOOL');
+ }
+
+ protected function getTablePrimaryRow() {
+ return self::FIELD_ID;
+ }
+
+ // -----------------------------------------------
+ // Private methods
+ // -----------------------------------------------
+
+ /**
+ * Builds the condition using specific user name.
+ *
+ * @param $user
+ * @return string
+ */
+ private function getUserCondition($user) {
+ return " `" . self::FIELD_USER . "`='$user'";
+ }
+
+}
\ No newline at end of file