diff --git a/plugins/tidypics/actions/addalbum.php b/plugins/tidypics/actions/addalbum.php new file mode 100644 index 0000000000000000000000000000000000000000..8df488a9208f75d842274a455b0bd1a103153243 --- /dev/null +++ b/plugins/tidypics/actions/addalbum.php @@ -0,0 +1,74 @@ +<?php + /** + * Tidypics Add New Album Action + * + */ + + // Make sure we're logged in + gatekeeper(); + + // Get input data + $title = get_input('tidypicstitle'); + $body = get_input('tidypicsbody'); + $tags = get_input('tidypicstags'); + $access = get_input('access_id'); + $container_guid = get_input('container_guid', $_SESSION['user']->getGUID()); + + // Cache to the session + $_SESSION['tidypicstitle'] = $title; + $_SESSION['tidypicsbody'] = $body; + $_SESSION['tidypicstags'] = $tags; + + // Convert string of tags into a preformatted array + $tagarray = string_to_tag_array($tags); + // Make sure the title isn't blank + if (empty($title)) { + register_error(elgg_echo("album:blank")); + forward($_SERVER['HTTP_REFERER']); //failed, so forward to previous page + // Otherwise, save the album + } else { + + // Initialise a new ElggObject + $album = new ElggObject(); + // Tell the system it's an album + $album->subtype = "album"; + + // Set its owner to the current user + $album->container_guid = $container_guid; + $album->owner_guid = $_SESSION['user']->getGUID(); + $album->access_id = $access; + // Set its title and description appropriately + $album->title = $title; + $album->description = $body; + + // we catch the adding images to new albums in the upload action and throw a river new album event + $album->new_album = TP_NEW_ALBUM; + + // Before we can set metadata, we need to save the album + if (!$album->save()) { + register_error(elgg_echo("album:error")); + forward(get_input('forward_url', $_SERVER['HTTP_REFERER'])); //failed, so forward to previous page + } + + // Now let's add tags + if (is_array($tagarray)) { + $album->tags = $tagarray; + } + + + + // Success message + system_message(elgg_echo("album:created")); + + // Remove the album post cache + unset($_SESSION['tidypicstitle']); + unset($_SESSION['tidypicsbody']); + unset($_SESSION['tidypicstags']); + + // plugins can register to be told when a new Tidypics album has been created + trigger_elgg_event('add', 'tp_album', $album); + + forward("pg/photos/upload/" . $album->guid); + } + +?> \ No newline at end of file diff --git a/plugins/tidypics/actions/addtag.php b/plugins/tidypics/actions/addtag.php new file mode 100644 index 0000000000000000000000000000000000000000..56268783e59748ea4d84feac8549698babfa7f05 --- /dev/null +++ b/plugins/tidypics/actions/addtag.php @@ -0,0 +1,104 @@ +<?php + /** + * Tidypics Add Photo Tag + * + */ + + gatekeeper(); + action_gatekeeper(); + + $coordinates_str = get_input('coordinates'); + + $user_id = get_input('user_id'); + $image_guid = get_input('image_guid'); + $word = get_input('word'); + + if ($image_guid == 0) { + register_error(elgg_echo("tidypics:phototagging:error")); + forward($_SERVER['HTTP_REFERER']); + } + + $image = get_entity($image_guid); + if (!$image) + { + register_error(elgg_echo("tidypics:phototagging:error")); + forward($_SERVER['HTTP_REFERER']); + } + + // test for empty tag + if ($user_id == 0 && empty($word)) { + register_error(elgg_echo("tidypics:phototagging:error")); + forward($_SERVER['HTTP_REFERER']); + } + + + $new_word_tag = false; + if ($user_id != 0) { + $relationships_type = 'user'; + $value = $user_id; + } else { + $relationships_type = 'word'; + $value = $word; + + // check to see if the photo has this tag and add if not + if (!is_array($image->tags)) { + if ($image->tags != $word) { + $new_word_tag = true; + $tagarray = $image->tags . ',' . $word; + $tagarray = string_to_tag_array($tagarray); + } + } else { + if (!in_array($word, $image->tags)) { + $new_word_tag = true; + $tagarray = $image->tags; + $tagarray[] = $word; + } + } + } + + // add new tag now so it is available in search + if ($new_word_tag) { + $image->clearMetadata('tags'); + $image->tags = $tagarray; + } + + // create string for javascript tag object + $tag->coords = $coordinates_str; + $tag->type = $relationships_type; + $tag->value = $value; + + $access_id = $image->getAccessID(); + $owner_id = get_loggedin_userid(); + $tagger = get_loggedin_user(); + + //Save annotation + if ($image->annotate('phototag', serialize($tag), $access_id, $owner_id)) { + // if tag is a user id, add relationship for searching (find all images with user x) + if ($relationships_type === 'user') { + if (!check_entity_relationship($user_id, 'phototag', $image_guid)) { + add_entity_relationship($user_id, 'phototag', $image_guid); + + // also add this to the river - subject is image, object is the tagged user + if (function_exists('add_to_river')) + add_to_river('river/object/image/tag', 'tag', $image_guid, $user_id, $access_id); + + // notify user of tagging as long as not self + if ($owner_id != $user_id) + notify_user($user_id, $owner_id, elgg_echo('tidypics:tag:subject'), + sprintf( + elgg_echo('tidypics:tag:body'), + $image->title, + $tagger->name, + $image->getURL() + ) + ); + } + } + + system_message(elgg_echo("tidypics:phototagging:success")); + } + + + forward($_SERVER['HTTP_REFERER']); + +?> diff --git a/plugins/tidypics/actions/create_thumbnails.php b/plugins/tidypics/actions/create_thumbnails.php new file mode 100644 index 0000000000000000000000000000000000000000..09743eef69a197136d3dcc43fd0b9d290d39cf8f --- /dev/null +++ b/plugins/tidypics/actions/create_thumbnails.php @@ -0,0 +1,61 @@ +<?php + /** + * Tidypics Thumbnail Creation Test + * + * Called through ajax + */ + + include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + include dirname(dirname(__FILE__)) . "/lib/resize.php"; + + global $CONFIG; + + $guid = $_GET['guid']; + + $image = get_entity($guid); + if (!$image || !($image instanceof TidypicsImage)) { + echo "Unable to get original image"; + return; + } + + $filename = $image->getFilename(); + $container_guid = $image->container_guid; + if (!$filename || !$container_guid) { + echo "Error retrieving information about the image"; + return; + } + + $title = $image->title; + $prefix = "image/" . $container_guid . "/"; + $filestorename = substr($filename, strlen($prefix)); + + $image_lib = get_plugin_setting('image_lib', 'tidypics'); + if (!$image_lib) + $image_lib = "GD"; + + if ($image_lib == 'ImageMagick') { // ImageMagick command line + + if (tp_create_im_cmdline_thumbnails($image, $prefix, $filestorename) != true) { + trigger_error('Tidypics warning: failed to create thumbnails - ImageMagick command line', E_USER_WARNING); + echo "Failed to create thumbnails"; + } + + } else if ($image_lib == 'ImageMagickPHP') { // imagick PHP extension + + if (tp_create_imagick_thumbnails($image, $prefix, $filestorename) != true) { + trigger_error('Tidypics warning: failed to create thumbnails - ImageMagick PHP', E_USER_WARNING); + echo "Failed to create thumbnails"; + } + + } else { + + if (tp_create_gd_thumbnails($image, $prefix, $filestorename) != true) { + trigger_error('Tidypics warning: failed to create thumbnails - GD', E_USER_WARNING); + echo "Failed to create thumbnails"; + } + + } // end of image library selector + + echo "<img id=\"tidypics_image\" src=\"{$CONFIG->wwwroot}mod/tidypics/thumbnail.php?file_guid={$guid}&size=large\" alt=\"{$title}\" />"; + +?> diff --git a/plugins/tidypics/actions/delete.php b/plugins/tidypics/actions/delete.php new file mode 100644 index 0000000000000000000000000000000000000000..cab996ec5e511b9a3758c9df5c013881f444c52a --- /dev/null +++ b/plugins/tidypics/actions/delete.php @@ -0,0 +1,121 @@ +<?php + + /** + * Tidypics Delete Action for Images and Albums + * + */ + + // must be logged in + gatekeeper(); + + $forward_url = 'pg/photos/world'; // by default forward to world photos + + $guid = (int) get_input('guid'); + + $entity = get_entity($guid); + if (!$entity) { // unable to get Elgg entity + register_error(elgg_echo("tidypics:deletefailed")); + forward($forward_url); + } + + if (!$entity->canEdit()) { // user doesn't have permissions + register_error(elgg_echo("tidypics:deletefailed")); + forward($forward_url); + } + + $subtype = $entity->getSubtype(); + $container = get_entity($entity->container_guid); + + if ($subtype != 'image' && $subtype != 'album') { // how did we even get here? + register_error(elgg_echo("tidypics:deletefailed")); + forward($forward_url); + } + + $owner_guid = 0; // group or user + if ($subtype == 'image') { //deleting an image + $album = get_entity($entity->container_guid); + $owner_guid = $album->container_guid; + $forward_url = $container->getURL(); //forward back to album after deleting pictures + $images = array($entity); + // plugins can register to be told when a Tidypics image has been deleted + trigger_elgg_event('delete', 'tp_image', $entity); + } else { //deleting an album + $owner_guid = $entity->container_guid; + $forward_url = 'pg/photos/owned/' . $container->username; + //get all the images from this album as long as less than 999 images + $images = get_entities("object", "image", $guid, '', 999); + // plugins can register to be told when a Tidypics album has been deleted + trigger_elgg_event('delete', 'tp_album', $entity); + } + + // make sure we decrease the repo size for the size quota + $image_repo_size_md = get_metadata_byname($owner_guid, "image_repo_size"); + $image_repo_size = (int)$image_repo_size_md->value; + + //loop through all images and delete them + foreach($images as $im) { + $thumbnail = $im->thumbnail; + $smallthumb = $im->smallthumb; + $largethumb = $im->largethumb; + + if ($thumbnail) { //delete standard thumbnail image + $delfile = new ElggFile(); + $delfile->owner_guid = $im->getOwner(); + $delfile->setFilename($thumbnail); + $delfile->delete(); + } + if ($smallthumb) { //delete small thumbnail image + $delfile = new ElggFile(); + $delfile->owner_guid = $im->getOwner(); + $delfile->setFilename($smallthumb); + $delfile->delete(); + } + if ($largethumb) { //delete large thumbnail image + $delfile = new ElggFile(); + $delfile->owner_guid = $im->getOwner(); + $delfile->setFilename($largethumb); + $delfile->delete(); + } + if ($im) { //delete actual image file + $delfile = new ElggFile($im->getGUID()); + $delfile->owner_guid = $im->getOwner(); + //$delfile->setFilename($im->originalfilename); + $image_repo_size -= $delfile->size(); + + if (!$delfile->delete()) { + if ($subtype=='image') register_error(elgg_echo("tidypics:deletefailed")); //unable to delete object + } else { + if ($subtype=='image') system_message(elgg_echo("tidypics:deleted")); //successfully deleted object + } + } //end delete actual image file + } //end looping through each image to delete it + + //now that all images have been deleted, delete the album + if ($subtype == 'album') { + //delete the album's directory manually; first create a temp file to get the directory path + $tmpfile = new ElggFile(); + $tmpfile->setFilename('image/' . $guid . '/._tmp_del_tidypics_album_'); + $tmpfile->subtype = 'image'; + $tmpfile->container_guid = $guid; + $tmpfile->open("write"); + $tmpfile->write(''); + $tmpfile->close(); + $tmpfile->save(); + $albumdir = eregi_replace('/._tmp_del_tidypics_album_', '', $tmpfile->getFilenameOnFilestore()); + $tmpfile->delete(); + if (is_dir($albumdir)) + rmdir($albumdir); + + //delete object from database + if (!$entity->delete()) { + register_error(elgg_echo("tidypics:deletefailed")); //unable to delete object + } else { + system_message(elgg_echo("tidypics:deleted")); //successfully deleted object + } + } //end of delete album + + create_metadata($owner_guid, "image_repo_size", $image_repo_size, 'integer', $owner_guid); + + forward($forward_url); + +?> \ No newline at end of file diff --git a/plugins/tidypics/actions/deletetag.php b/plugins/tidypics/actions/deletetag.php new file mode 100644 index 0000000000000000000000000000000000000000..becf1fedb5a1c6ccce3073c568407291ed93ecd9 --- /dev/null +++ b/plugins/tidypics/actions/deletetag.php @@ -0,0 +1,57 @@ +<?php + /** + * Tidypics Delete Photo Tag + * + */ + + gatekeeper(); + action_gatekeeper(); + + $image_guid = get_input('image_guid'); + $tags = get_input('tags'); + + + if ($image_guid == 0) { + register_error(elgg_echo("tidypics:phototagging:error")); + forward($_SERVER['HTTP_REFERER']); + } + + $image = get_entity($image_guid); + if (!$image) + { + register_error(elgg_echo("tidypics:phototagging:error")); + forward($_SERVER['HTTP_REFERER']); + } + + foreach ($tags as $id => $value) { + // delete normal tag if it exists + if (is_array($image->tags)) { + $index = array_search($value, $image->tags); + if ($index !== false) { + $tagarray = $image->tags; + unset($tagarray[$index]); + $image->clearMetadata('tags'); + $image->tags = $tagarray; + } + } else { + if ($value === $image->tags) { + $image->clearMetadata('tags'); + } + } + + // delete relationship if this tag is a user + $annotation = get_annotation($id); + $photo_tag = unserialize($annotation->value); + if ($photo_tag->type == 'user') { + remove_entity_relationship($photo_tag->value, 'phototag', $image_guid); + } + + // delete the photo tag annotation + delete_annotation($id); + } + + system_message(elgg_echo("tidypics:deletetag:success")); + + forward($_SERVER['HTTP_REFERER']); + +?> diff --git a/plugins/tidypics/actions/edit.php b/plugins/tidypics/actions/edit.php new file mode 100644 index 0000000000000000000000000000000000000000..cdf9420b24547fcb910e166b93758e0b080f6a30 --- /dev/null +++ b/plugins/tidypics/actions/edit.php @@ -0,0 +1,81 @@ +<?php + + /** + * Tidypics edit album/image action + * + */ + + // Make sure we're logged in + gatekeeper(); + + // Get input data + $guid = (int) get_input('guid'); // guid of image or album + $title = get_input('tidypicstitle'); + $body = get_input('tidypicsbody'); + $access = get_input('access_id'); + $tags = get_input('tidypicstags'); + $subtype = get_input('subtype'); + $cover = get_input('cover'); + if (is_array($cover)) $cover = $cover[0]; + + $container_guid = get_input('container_guid'); + + // Make sure we actually have permission to edit + $entity = get_entity($guid); + if (!$entity->canEdit()) { + forward(); + } + + // Get owning user/group + $owner = get_entity($entity->getOwner()); + + // change access only if access is different from current + if ($subtype == 'album' && $entity->access_id != $access) { + $entity->access_id = $access; + + //get images from album and update access on image entities + $images = get_entities("object","image", $guid, '', 999, '', false); + foreach ($images as $im) { + $im->access_id = $access; + $im->save(); + } + } + + + // Set its title and description appropriately + $entity->title = $title; + $entity->description = $body; + + // Before we can set metadata, we need to save the entity + if (!$entity->save()) { + register_error(elgg_echo("album:error")); + $entity->delete(); + forward($_SERVER['HTTP_REFERER']); //failed, so forward to previous page + } + + // Now let's add tags + $tagarray = string_to_tag_array($tags); + $entity->clearMetadata('tags'); + if (is_array($tagarray)) { + $entity->tags = $tagarray; + } + + //if cover meta is sent from image save as metadata + if ($subtype == 'image' && $cover == elgg_echo('album:cover')) { + $album = get_entity($container_guid); + $album->cover = $entity->guid; + } + + // Success message + if ($subtype == 'album') { + system_message(elgg_echo("album:edited")); + // plugins can register to be told when a Tidypics album has been updated + trigger_elgg_event('update', 'tp_album', $entity); + } else { + system_message(elgg_echo('images:edited')); + // plugins can register to be told when a Tidypics image has been updated + trigger_elgg_event('update', 'tp_image', $entity); + } + + forward($entity->getURL()); +?> diff --git a/plugins/tidypics/actions/edit_multi.php b/plugins/tidypics/actions/edit_multi.php new file mode 100644 index 0000000000000000000000000000000000000000..c7099e6dbec061e34b36536556a0c18dde320b34 --- /dev/null +++ b/plugins/tidypics/actions/edit_multi.php @@ -0,0 +1,66 @@ +<?php + /** + * Elgg album: multi image edit action + * + * This is called when uploading images + */ + + // Make sure we're logged in + gatekeeper(); + + // Get input data + $title_array = get_input('title'); + $caption_array = get_input('caption'); + $tags_array = get_input('tags'); + $image_guid_array = get_input('image_guid'); + $container_guid = get_input('container_guid'); + $album_entity = get_entity($container_guid); + $cover = get_input('cover'); + $not_updated = array(); + + foreach($image_guid_array as $key => $im) { + $image = get_entity($im); + + if ($image->canEdit()) { + + // Convert string of tags into a preformatted array + $tagarray = string_to_tag_array($tags_array[$key]); + + //set title appropriately + if ($title_array[$key]) + $image->title = $title_array[$key]; + else + $image->title = substr($image->originalfilename, 0, strrpos($image->originalfilename, '.')); + + //set description appropriately + $image->description = $caption_array[$key]; + + // Before we can set metadata, we need to save the image + if (!$image->save()) { + array_push($not_updated, $image->guid); + } + + // Now let's add tags. We can pass an array directly to the object property! Easy. + $image->clearMetadata('tags'); + if (is_array($tagarray)) { + $image->tags = $tagarray; + } + + //if cover meta is sent from image save as metadata + if ($cover == $im) { + $album_entity->cover = $im; + } + } + } + + // Success message + if (count($not_updated) > 0) { + register_error(elgg_echo("images:notedited")); + } else { + system_message(elgg_echo("images:edited")); + } + + // Forward to the main album page + forward($album_entity->getURL()); + +?> \ No newline at end of file diff --git a/plugins/tidypics/actions/flickrImportPhotoset.php b/plugins/tidypics/actions/flickrImportPhotoset.php new file mode 100644 index 0000000000000000000000000000000000000000..ec0d65b5dce884b2f0b29a3c29fe8d62eadb2d91 --- /dev/null +++ b/plugins/tidypics/actions/flickrImportPhotoset.php @@ -0,0 +1,340 @@ +<?php +/** + * Import a whole bunch of photos from flickr + */ + +// Load Elgg engine +include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + +require_once( dirname(dirname(__FILE__)) . "/lib/flickr.php" ); +require_once dirname(dirname(__FILE__)) . "/lib/phpFlickr/phpFlickr.php"; +$f = new phpFlickr("26b2abba37182aca62fe0eb2c7782050"); + +$set_id = get_input( "set_id" ); +$album_id = get_input( "album_id" ); +$page_pp = get_input( "page" ); +$return_url = get_input( "return_url" ); +$user = get_loggedin_user(); +$flickr_id = get_metadata_byname( $user->guid, "flickr_id" ); + +if( empty( $flickr_id )) { + register_error( elgg_echo( 'flickr:errorusername2' )); + forward( $return_url ); + die; //just in case +} + +// Get the friendly URL of the user's photos +$photos_url = $f->urls_getUserPhotos( $flickr_id->value ); +$photos = $f->photosets_getPhotos( $set_id, null, null, 10, $page_pp ); + +$photos_to_upload = array(); +foreach( $photos["photoset"]["photo"] as $photo ) { + + //check if we already have this image + $meta = get_metadata_byname( $user->guid, $photo["id"] ); + if( $meta->value == 1 ) { //we've downloaded this already + register_error( elgg_echo( 'flickr:errorimageimport' )); + continue; + } + //store this so we don't download the same photo multiple times + create_metadata( $user->guid, $photo["id"], "1", "text", $user->guid, ACCESS_PUBLIC ); + + $photo_info = $f->photos_getInfo( $photo["id"], $photo["secret"] ); + $tags = array(); + foreach( $photo_info["tags"]["tag"] as $tag ) { + $tags[] = $tag["raw"]; + } + $tags = implode( ", ", $tags ); + + $image_url = $f->buildPhotoURL( $photo ); + $photos_to_upload[ $photo_info["id"] . ".jpg" ] = array( "url"=> $image_url, "tags" => $tags, "title" => $photo_info["title"], "description" => $photo_info["description"], "flickr_page" => "$photos_url$photo[id]" ); + + $body .= "<div class='tidypics_album_images'>"; + $body .= "$photo_info[title]<br />Views: $photo_info[views]<br />"; + $body .= "<a href=$photos_url$photo[id]>"; + $body .= "<img border='0' alt='$photo[title]' ". + "src='$image_url' />"; + $body .= "</a>"; +} +// echo "<pre>"; var_dump( $photos_to_upload );; die; + +/** + * Elgg multi-image uploader action +* +* This will upload up to 10 images at at time to an album + */ + +global $CONFIG; +include dirname(dirname(__FILE__)) . "/lib/resize.php"; +include dirname(dirname(__FILE__)) . "/lib/exif.php"; + +// Make sure we're logged in +gatekeeper(); + +// Get common variables +$access_id = (int) get_input("access_id"); +$container_guid = (int) get_input('container_guid', 0); +$container_guid = intval ($album_id); + +$album = get_entity($container_guid); + +$maxfilesize = (float) get_plugin_setting('maxfilesize','tidypics'); +if (!$maxfilesize) + $maxfilesize = 5; // default to 5 MB if not set +$maxfilesize = 1024 * 1024 * $maxfilesize; // convert to bytes from MBs + +$quota = get_plugin_setting('quota','tidypics'); +$quota = 1024 * 1024 * $quota; +$image_repo_size_md = get_metadata_byname($album->container_guid, "image_repo_size"); +$image_repo_size = (int)$image_repo_size_md->value; + +$image_lib = get_plugin_setting('image_lib', 'tidypics'); +if (!$image_lib) + $image_lib = "GD"; + +/* +// post limit exceeded +if (count($_FILES) == 0) { + trigger_error('Tidypics warning: user exceeded post limit on image upload', E_USER_WARNING); + register_error(elgg_echo('tidypics:exceedpostlimit')); + forward(get_input('forward_url', $_SERVER['HTTP_REFERER'])); +} +*/ + +/* +// test to make sure at least 1 image was selected by user +$num_images = 0; +foreach($_FILES as $key => $sent_file) { + if (!empty($sent_file['name'])) + $num_images++; +} +*/ +if ( count( $photos_to_upload ) == 0 ) { + // have user try again + register_error(elgg_echo('tidypics:noimages')); + forward(get_input('forward_url', $_SERVER['HTTP_REFERER'])); + die; //just in case +} + +$uploaded_images = array(); +$not_uploaded = array(); +$error_msgs = array(); + +$img_river_view = get_plugin_setting('img_river_view', 'tidypics'); + +/* +$accepted_formats = array( + 'image/jpeg', + 'image/png', + 'image/gif', + 'image/pjpeg', + 'image/x-png', + ); + +*/ +//foreach($_FILES as $key => $sent_file) { +foreach( $photos_to_upload as $name => $photo ) { + +/* + // skip empty entries + if (empty($sent_file['name'])) + continue; + + $name = $sent_file['name']; + $mime = $sent_file['type']; + + if ($sent_file['error']) { + array_push($not_uploaded, $sent_file['name']); + if ($sent_file['error'] == 1) { + trigger_error('Tidypics warning: image exceed server php upload limit', E_USER_WARNING); + array_push($error_msgs, elgg_echo('tidypics:image_mem')); + } + else { + array_push($error_msgs, elgg_echo('tidypics:unk_error')); + } + continue; + } + + //make sure file is an image + if (!in_array($mime, $accepted_formats)) { + array_push($not_uploaded, $sent_file['name']); + array_push($error_msgs, elgg_echo('tidypics:not_image')); + continue; + } + +*/ +/* I'm not going to check filesize here because flickr has already resized it for me + // check quota + if ($quota) { + if ($image_repo_size + $sent_file['size'] > $quota) { + array_push($not_uploaded, $sent_file['name']); + array_push($error_msgs, elgg_echo('tidypics:exceed_quota')); + continue; + } + } + + // make sure file does not exceed memory limit + if ($sent_file['size'] > $maxfilesize) { + array_push($not_uploaded, $sent_file['name']); + array_push($error_msgs, elgg_echo('tidypics:image_mem')); + continue; + } + + // make sure the in memory image size does not exceed memory available - GD only + $imginfo = getimagesize($sent_file['tmp_name']); + $mem_avail = ini_get('memory_limit'); + $mem_avail = rtrim($mem_avail, 'M'); + $mem_avail = $mem_avail * 1024 * 1024; + if ($image_lib == 'GD') { + $mem_required = ceil(5.35 * $imginfo[0] * $imginfo[1]); + + $mem_used = memory_get_usage(); + + $mem_avail = $mem_avail - $mem_used - 2097152; // 2 MB buffer + if ($mem_required > $mem_avail) { + array_push($not_uploaded, $sent_file['name']); + array_push($error_msgs, elgg_echo('tidypics:image_pixels')); + trigger_error('Tidypics warning: image memory size too large for resizing so rejecting', E_USER_WARNING); + continue; + } + } else if ($image_lib == 'ImageMagickPHP') { + // haven't been able to determine a limit like there is for GD + } +*/ + $mime = "image/jpeg"; //not sure how to get this from the file if we aren't posting it + + //this will save to users folder in /image/ and organize by photo album + $prefix = "image/" . $container_guid . "/"; + $file = new ElggFile(); + $filestorename = strtolower(time().$name); + $file->setFilename($prefix.$filestorename . ".jpg"); //that's all flickr stores so I think this is safe + $file->setMimeType($mime); + $file->originalfilename = $name; + $file->subtype="image"; + $file->simpletype="image"; + $file->access_id = $access_id; + if ($container_guid) { + $file->container_guid = $container_guid; + } + + // get the file from flickr and save it locally + $filename = $file->getFilenameOnFilestore(); + $destination=fopen($filename,"w"); + $source=fopen($photo["url"],"r"); + + while ($a=fread($source,1024)) fwrite($destination,$a); + fclose($source); + fclose($destination); + + /* + $file->open("write"); + $file->write(); + $file->write(get_uploaded_file($key)); + $file->close(); + */ + $result = $file->save(); + + if (!$result) { + array_push($not_uploaded, $sent_file['name']); + array_push($error_msgs, elgg_echo('tidypics:save_error')); + continue; + } + + //add tags + create_metadata( $file->guid, "tags", $photo["tags"], "text", $user->guid, ACCESS_PUBLIC ); + + //add title and description + create_object_entity( $file->guid, $photo["title"], $photo["description"] ); + + //get and store the exif data + td_get_exif($file); + + // resize photos to create thumbnails + if ($image_lib == 'ImageMagick') { // ImageMagick command line + + if (tp_create_im_cmdline_thumbnails($file, $prefix, $filestorename) != true) { + trigger_error('Tidypics warning: failed to create thumbnails - ImageMagick command line', E_USER_WARNING); + } + + } else if ($image_lib == 'ImageMagickPHP') { // imagick php extension + + if (tp_create_imagick_thumbnails($file, $prefix, $filestorename) != true) { + trigger_error('Tidypics warning: failed to create thumbnails - ImageMagick PHP', E_USER_WARNING); + } + + } else { + + if (tp_create_gd_thumbnails($file, $prefix, $filestorename) != true) { + trigger_error('Tidypics warning: failed to create thumbnails - GD', E_USER_WARNING); + } + + } // end of image library selector + + //keep one file handy so we can add a notice to the river if single image option selected + if(!$file_for_river) { + $file_for_river = $file; + } + + array_push($uploaded_images, $file->guid); + + // update user/group size for checking quota + $image_repo_size += $sent_file['size']; + + // successful upload so check if this is a new album and throw river event/notification if so + if ($album->new_album == TP_NEW_ALBUM) { + $album->new_album = TP_OLD_ALBUM; + + // we throw the notification manually here so users are not told about the new album until there + // is at least a few photos in it + object_notifications('create', 'object', $album); + + if (function_exists('add_to_river')) + add_to_river('river/object/album/create', 'create', $album->owner_guid, $album->guid); + } + + if ($img_river_view == "all") { + add_to_river('river/object/image/create', 'create', $file->getObjectOwnerGUID(), $file->getGUID()); + } + unset($file); // may not be needed but there seems to be a memory leak + +} //end of for loop + +if (count($not_uploaded) > 0) { + if (count($uploaded_images) > 0) + $error = sprintf(elgg_echo("tidypics:partialuploadfailure"), count($not_uploaded), count($not_uploaded) + count($uploaded_images)) . '<br />'; + else + $error = elgg_echo("tidypics:completeuploadfailure") . '<br />'; + + $num_failures = count($not_uploaded); + for ($i = 0; $i < $num_failures; $i++) { + $error .= "{$not_uploaded[$i]}: {$error_msgs[$i]} <br />"; + } + register_error($error); + + if (count($uploaded_images) == 0) + forward(get_input('forward_url', $_SERVER['HTTP_REFERER'])); //upload failed, so forward to previous page + else { + // some images did upload so we fall through + } +} else { + system_message(elgg_echo('tidypics:upl_success')); +} + +if (count($uploaded_images) && $img_river_view == "1") { + if (function_exists('add_to_river')) { + add_to_river('river/object/image/create', 'create', $file_for_river->getObjectOwnerGUID(), $file_for_river->getGUID()); + } +} + +// update image repo size +create_metadata($album->container_guid, "image_repo_size", $image_repo_size, 'integer', $album->container_guid); + +// plugins can register to be told when a Tidypics album has had images added +trigger_elgg_event('upload', 'tp_album', $album); + +//forward to multi-image edit page + +$url = $CONFIG->wwwroot . 'mod/tidypics/pages/edit_multiple.php?files=' . implode('-', $uploaded_images); +forward($url); + +?> diff --git a/plugins/tidypics/actions/flickrSetup.php b/plugins/tidypics/actions/flickrSetup.php new file mode 100644 index 0000000000000000000000000000000000000000..fbc519b02016d6a77650848bdeb8054096ac3fb9 --- /dev/null +++ b/plugins/tidypics/actions/flickrSetup.php @@ -0,0 +1,38 @@ +<?php +/** + * Setup the user's flickr username and store it + */ +require_once dirname(dirname(__FILE__)) . "/lib/phpFlickr/phpFlickr.php"; +$f = new phpFlickr("26b2abba37182aca62fe0eb2c7782050"); + +$flickr_username = get_input( "flickr_username" ); +$album_id = get_input( "album_id" ); +$return_url = get_input( "return_url" ); +$user = get_loggedin_user(); + +if( empty( $flickr_username )) { + register_error( elgg_echo( 'flickr:enterusername' )); + forward( $return_url ); + die; //just in case +} else { + $flickr_user = $f->people_findByUsername( $flickr_username ); + if( !empty( $flickr_user["id"] )) { + create_metadata( $user->guid, "flickr_username", $flickr_username, "text", $user->guid, ACCESS_PUBLIC ); + create_metadata( $user->guid, "flickr_id", $flickr_user["id"], "text", $user->guid, ACCESS_PUBLIC ); + if( $album_id ) { + create_metadata( $user->guid, "flickr_album_id", $album_id, "text", $user->guid, ACCESS_PUBLIC ); + $album = get_entity( $album_id ); + } + + system_message( sprintf( elgg_echo( 'flickr:savedusername' ), $flickr_username )); + system_message( sprintf( elgg_echo( 'flickr:saveduserid' ), $flickr_user["id"] )); + system_message( sprintf( elgg_echo( 'flickr:savedalbum' ), $album->title )); + } else { + register_error( sprintf( elgg_echo( 'flickr:errorusername' ), $flickr_username )); + } +} + +forward($_SERVER['HTTP_REFERER']); +//echo "<pre>"; var_dump( array($flickr_username, $return_url )); echo "</pre>"; + +?> \ No newline at end of file diff --git a/plugins/tidypics/actions/imtest.php b/plugins/tidypics/actions/imtest.php new file mode 100644 index 0000000000000000000000000000000000000000..cbe15a1c165264f8d28082e88ec66cf92b3c270c --- /dev/null +++ b/plugins/tidypics/actions/imtest.php @@ -0,0 +1,19 @@ +<?php + /** + * Tidypics ImageMagick Location Test + * + * Called through ajax + */ + + $location = $_GET['location']; + + $command = $location . "convert -version"; + + $result = system($command, $return_val); + + if ($return_val == 0) { + echo $result; + } else { + echo "Unable to run ImageMagick. Please check the path."; + } +?> diff --git a/plugins/tidypics/actions/settings.php b/plugins/tidypics/actions/settings.php new file mode 100644 index 0000000000000000000000000000000000000000..a4f102b894b6f26c9204d1c96157488f6755b89e --- /dev/null +++ b/plugins/tidypics/actions/settings.php @@ -0,0 +1,72 @@ +<?php + /** + * Save settings of Tidypics + * + */ + + global $CONFIG; + + admin_gatekeeper(); + action_gatekeeper(); + + + // Params array (text boxes and drop downs) + $params = get_input('params'); + $result = false; + foreach ($params as $k => $v) { + if (!set_plugin_setting($k, $v, 'tidypics')) { + register_error(sprintf(elgg_echo('plugins:settings:save:fail'), 'tidypics')); + forward($_SERVER['HTTP_REFERER']); + } + } + + // check boxes + if (is_array(get_input('download_link'))) // this can be done due to way Elgg uses checkboxes + set_plugin_setting('download_link', 'enabled', 'tidypics'); + else + set_plugin_setting('download_link', 'disabled', 'tidypics'); + + if (is_array(get_input('tagging'))) + set_plugin_setting('tagging', 'enabled', 'tidypics'); + else + set_plugin_setting('tagging', 'disabled', 'tidypics'); + + if (is_array(get_input('photo_ratings'))) + set_plugin_setting('photo_ratings', 'enabled', 'tidypics'); + else + set_plugin_setting('photo_ratings', 'disabled', 'tidypics'); + + if (is_array(get_input('exif'))) + set_plugin_setting('exif', 'enabled', 'tidypics'); + else + set_plugin_setting('exif', 'disabled', 'tidypics'); + + if (is_array(get_input('view_count'))) + set_plugin_setting('view_count', 'enabled', 'tidypics'); + else + set_plugin_setting('view_count', 'disabled', 'tidypics'); + + if (is_array(get_input('grp_perm_override'))) + set_plugin_setting('grp_perm_override', 'enabled', 'tidypics'); + else + set_plugin_setting('grp_perm_override', 'disabled', 'tidypics'); + + + // image sizes + $image_sizes = array(); + $image_sizes['large_image_width'] = get_input('large_thumb_width'); + $image_sizes['large_image_height'] = get_input('large_thumb_height'); + $image_sizes['small_image_width'] = get_input('small_thumb_width'); + //$image_sizes['small_image_height'] = get_input('small_thumb_height'); + $image_sizes['small_image_height'] = get_input('small_thumb_width'); + $image_sizes['thumb_image_width'] = get_input('thumb_width'); + //$image_sizes['thumb_image_height'] = get_input('thumb_height'); + $image_sizes['thumb_image_height'] = get_input('thumb_width'); + set_plugin_setting('image_sizes', serialize($image_sizes), 'tidypics'); + + + + system_message(elgg_echo('tidypics:settings:save:ok')); + + forward($_SERVER['HTTP_REFERER']); +?> diff --git a/plugins/tidypics/actions/upgrade.php b/plugins/tidypics/actions/upgrade.php new file mode 100644 index 0000000000000000000000000000000000000000..cb200380abeb6e8dacc40f28011165491c80d694 --- /dev/null +++ b/plugins/tidypics/actions/upgrade.php @@ -0,0 +1,40 @@ +<?php + +/******************************************** + * + * Upgrade from Tidypics 1.5 to 1.6 + * + *********************************************/ + + include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + + admin_gatekeeper(); + + $result = true; + + // add image class + $id = get_subtype_id("object", "image"); + if ($id != 0) { + $table = $CONFIG->dbprefix . 'entity_subtypes'; + $result = update_data("UPDATE {$table} set class='TidypicsImage' where id={$id}"); + if (!result) { + register_error(elgg_echo('tidypics:upgrade:failed')); + forward($_SERVER['HTTP_REFERER']); + } + } + + // add album class + $id = get_subtype_id("object", "album"); + if ($id != 0) { + $table = $CONFIG->dbprefix . 'entity_subtypes'; + $result = update_data("UPDATE {$table} set class='TidypicsAlbum' where id={$id}"); + if (!result) { + register_error(elgg_echo('tidypics:upgrade:failed')); + forward($_SERVER['HTTP_REFERER']); + } + } + + system_message(elgg_echo('tidypics:upgrade:success')); + + forward($_SERVER['HTTP_REFERER']); +?> \ No newline at end of file diff --git a/plugins/tidypics/actions/upload.php b/plugins/tidypics/actions/upload.php new file mode 100644 index 0000000000000000000000000000000000000000..b1eb4efe13848d3ae40fb314ee0d2c22064868e5 --- /dev/null +++ b/plugins/tidypics/actions/upload.php @@ -0,0 +1,252 @@ +<?php +/** + * Elgg multi-image uploader action + * + * This will upload up to 10 images at at time to an album + */ + +include dirname(dirname(__FILE__)) . "/lib/resize.php"; +include dirname(dirname(__FILE__)) . "/lib/exif.php"; + +// Get common variables +$access_id = (int) get_input("access_id"); +$container_guid = (int) get_input('container_guid', 0); +$album = get_entity($container_guid); +if (!$album) { + register_error(elgg_echo('tidypics:baduploadform')); + forward($_SERVER['HTTP_REFERER']); +} + +$maxfilesize = (float) get_plugin_setting('maxfilesize','tidypics'); +if (!$maxfilesize) { + $maxfilesize = 5; // default to 5 MB if not set +} +$maxfilesize = 1024 * 1024 * $maxfilesize; // convert to bytes from MBs + +$quota = get_plugin_setting('quota','tidypics'); +$quota = 1024 * 1024 * $quota; +$image_repo_size_md = get_metadata_byname($album->container_guid, "image_repo_size"); +$image_repo_size = (int)$image_repo_size_md->value; + +$image_lib = get_plugin_setting('image_lib', 'tidypics'); +if (!$image_lib) { + $image_lib = "GD"; +} + +// post limit exceeded +if (count($_FILES) == 0) { + trigger_error('Tidypics warning: user exceeded post limit on image upload', E_USER_WARNING); + register_error(elgg_echo('tidypics:exceedpostlimit')); + forward($_SERVER['HTTP_REFERER']); +} + +// test to make sure at least 1 image was selected by user +$num_images = 0; +foreach($_FILES as $key => $sent_file) { + if (!empty($sent_file['name'])) { + $num_images++; + } +} +if ($num_images == 0) { + // have user try again + register_error(elgg_echo('tidypics:noimages')); + forward($_SERVER['HTTP_REFERER']); +} + +$uploaded_images = array(); +$not_uploaded = array(); +$error_msgs = array(); + +$img_river_view = get_plugin_setting('img_river_view', 'tidypics'); + +$accepted_formats = array( + 'image/jpeg', + 'image/png', + 'image/gif', + 'image/pjpeg', + 'image/x-png', +); + + +foreach($_FILES as $key => $sent_file) { + + // skip empty entries + if (empty($sent_file['name'])) { + continue; + } + + $name = $sent_file['name']; + $mime = $sent_file['type']; + + if ($sent_file['error']) { + array_push($not_uploaded, $sent_file['name']); + if ($sent_file['error'] == 1) { + trigger_error('Tidypics warning: image exceeded server php upload limit', E_USER_WARNING); + array_push($error_msgs, elgg_echo('tidypics:image_mem')); + } else { + array_push($error_msgs, elgg_echo('tidypics:unk_error')); + } + continue; + } + + //make sure file is an image + if (!in_array($mime, $accepted_formats)) { + array_push($not_uploaded, $sent_file['name']); + array_push($error_msgs, elgg_echo('tidypics:not_image')); + continue; + } + + // check quota + if ($quota) { + if ($image_repo_size + $sent_file['size'] > $quota) { + array_push($not_uploaded, $sent_file['name']); + array_push($error_msgs, elgg_echo('tidypics:exceed_quota')); + continue; + } + } + + // make sure file does not exceed memory limit + if ($sent_file['size'] > $maxfilesize) { + array_push($not_uploaded, $sent_file['name']); + array_push($error_msgs, elgg_echo('tidypics:image_mem')); + continue; + } + + // make sure the in memory image size does not exceed memory available - GD only + $imginfo = getimagesize($sent_file['tmp_name']); + $mem_avail = ini_get('memory_limit'); + $mem_avail = rtrim($mem_avail, 'M'); + $mem_avail = $mem_avail * 1024 * 1024; + if ($image_lib == 'GD') { + $mem_required = ceil(5.35 * $imginfo[0] * $imginfo[1]); + + $mem_used = memory_get_usage(); + + $mem_avail = $mem_avail - $mem_used - 2097152; // 2 MB buffer + if ($mem_required > $mem_avail) { + array_push($not_uploaded, $sent_file['name']); + array_push($error_msgs, elgg_echo('tidypics:image_pixels')); + trigger_error('Tidypics warning: image memory size too large for resizing so rejecting', E_USER_WARNING); + continue; + } + } else if ($image_lib == 'ImageMagickPHP') { + // haven't been able to determine a limit like there is for GD + } + + //this will save to users folder in /image/ and organize by photo album + $prefix = "image/" . $container_guid . "/"; + $file = new ElggFile(); + $filestorename = strtolower(time().$name); + $file->setFilename($prefix.$filestorename); + $file->setMimeType($mime); + $file->originalfilename = $name; + $file->subtype="image"; + $file->simpletype="image"; + $file->access_id = $access_id; + if ($container_guid) { + $file->container_guid = $container_guid; + } + $file->open("write"); + $file->write(get_uploaded_file($key)); + $file->close(); + $result = $file->save(); + + if (!$result) { + array_push($not_uploaded, $sent_file['name']); + array_push($error_msgs, elgg_echo('tidypics:save_error')); + continue; + } + + //get and store the exif data + td_get_exif($file); + + + // resize photos to create thumbnails + if ($image_lib == 'ImageMagick') { // ImageMagick command line + + if (tp_create_im_cmdline_thumbnails($file, $prefix, $filestorename) != true) { + trigger_error('Tidypics warning: failed to create thumbnails - ImageMagick command line', E_USER_WARNING); + } + + } else if ($image_lib == 'ImageMagickPHP') { // imagick php extension + + if (tp_create_imagick_thumbnails($file, $prefix, $filestorename) != true) { + trigger_error('Tidypics warning: failed to create thumbnails - ImageMagick PHP', E_USER_WARNING); + } + + } else { + + if (tp_create_gd_thumbnails($file, $prefix, $filestorename) != true) { + trigger_error('Tidypics warning: failed to create thumbnails - GD', E_USER_WARNING); + } + + } // end of image library selector + + //keep one file handy so we can add a notice to the river if single image option selected + if (!$file_for_river) { + $file_for_river = $file; + } + + array_push($uploaded_images, $file->guid); + + // update user/group size for checking quota + $image_repo_size += $sent_file['size']; + + // plugins can register to be told when a new image has been uploaded + trigger_elgg_event('upload', 'tp_image', $file); + + // successful upload so check if this is a new album and throw river event/notification if so + if ($album->new_album == TP_NEW_ALBUM) { + $album->new_album = TP_OLD_ALBUM; + + // we throw the notification manually here so users are not told about the new album until there + // is at least a few photos in it + object_notifications('create', 'object', $album); + + add_to_river('river/object/album/create', 'create', $album->owner_guid, $album->guid); + } + + if ($img_river_view == "all") { + add_to_river('river/object/image/create', 'create', $file->getObjectOwnerGUID(), $file->getGUID()); + } + unset($file); // may not be needed but there seems to be a memory leak + +} //end of for loop + +if (count($not_uploaded) > 0) { + if (count($uploaded_images) > 0) { + $error = sprintf(elgg_echo("tidypics:partialuploadfailure"), count($not_uploaded), count($not_uploaded) + count($uploaded_images)) . '<br />'; + } else { + $error = elgg_echo("tidypics:completeuploadfailure") . '<br />'; + } + + $num_failures = count($not_uploaded); + for ($i = 0; $i < $num_failures; $i++) { + $error .= "{$not_uploaded[$i]}: {$error_msgs[$i]} <br />"; + } + register_error($error); + + if (count($uploaded_images) == 0) { + //upload failed, so forward to previous page + forward($_SERVER['HTTP_REFERER']); + } else { + // some images did upload so we fall through + } +} else { + system_message(elgg_echo('tidypics:upl_success')); +} + + +if (count($uploaded_images) && $img_river_view == "1") { + add_to_river('river/object/image/create', 'create', $file_for_river->getObjectOwnerGUID(), $file_for_river->getGUID()); +} + +// update image repo size +create_metadata($album->container_guid, "image_repo_size", $image_repo_size, 'integer', $album->container_guid); + +// plugins can register to be told when a Tidypics album has had images added +trigger_elgg_event('upload', 'tp_album', $album); + + +//forward to multi-image edit page +forward($CONFIG->wwwroot . 'mod/tidypics/pages/edit_multiple.php?files=' . implode('-', $uploaded_images)); diff --git a/plugins/tidypics/contributions.txt b/plugins/tidypics/contributions.txt new file mode 100644 index 0000000000000000000000000000000000000000..3cea54bd9975e5d0e6dcd56048ce55f96428d62a --- /dev/null +++ b/plugins/tidypics/contributions.txt @@ -0,0 +1,364 @@ +Changelog and contributors list + + +------------------------------------------------------------------------ +Version 1.6.8 Change List +Release Date: 05/01/2010 +------------------------------------------------------------------------ +BEGIN VERSION 1.6.8 CHANGES +------------------------------------------------------------------------ + * New language strings: tidypics:nophotosingroup, tidypics:baduploadform + tidypics:settings:heading:img_lib, tidypics:settings:heading:main, + tidypics:settings:heading:river, tidypics:settings:heading:sizes, + tidypics:settings:heading:groups + * Fixed bug in titles of albums RSS + * Added a new css element: tidypics_line_break + * Fixed layout of album covers due to long titles or other text + * Fixed some bugs with image resizing when images are wide and short + * Improved interface of admin settings +------------------------------------------------------------------------ +END VERSION 1.6.8 CHANGES +------------------------------------------------------------------------ + +------------------------------------------------------------------------ +Version 1.6.7 Change List +Release Date: 04/24/2010 +------------------------------------------------------------------------ +BEGIN VERSION 1.6.7 CHANGES +------------------------------------------------------------------------ + * Added categories integration + * Added a better quota display message - includes percentage now + * Tweaked the css so that upload list is enumerated (#tidypics_image_upload_list) +------------------------------------------------------------------------ +END VERSION 1.6.7 CHANGES +------------------------------------------------------------------------ + +------------------------------------------------------------------------ +Version 1.6.6 Change List +Release Date: 03/06/2010 +------------------------------------------------------------------------ +BEGIN VERSION 1.6.6 CHANGES +------------------------------------------------------------------------ + * Tweaked slideshow start code + * Fixed bug with delete tags menu item + * Fixed bug in en.php + * Better error checking for ImageMagick resizing +------------------------------------------------------------------------ +END VERSION 1.6.6 CHANGES +------------------------------------------------------------------------ + +------------------------------------------------------------------------ +Version 1.6.5 Change List +Release Date: 12/12/2009 +------------------------------------------------------------------------ +BEGIN VERSION 1.6.5 CHANGES +------------------------------------------------------------------------ + * Bug fixes + * Better plugin hooks for adding slideshows and lightboxes + * Better display of album pages and tweaked css + * Slideshows available on more pages + * Made a change to parameters in tp_list_entities - added container + * Added Danish translation from erikernstm + * Added French translation from Fx Nion +------------------------------------------------------------------------ +END VERSION 1.6.5 CHANGES +------------------------------------------------------------------------ + + +------------------------------------------------------------------------ +Version 1.6.4 Change List +Release Date: 10/05/2009 +------------------------------------------------------------------------ +BEGIN VERSION 1.6.4 CHANGES +------------------------------------------------------------------------ + * Bug fixes + * Improved watermarking + * Add slideshow code by Torsten +------------------------------------------------------------------------ +END VERSION 1.6.4 CHANGES +------------------------------------------------------------------------ + +------------------------------------------------------------------------ +Version 1.6.3 Change List +Release Date: 09/13/2009 +------------------------------------------------------------------------ +BEGIN VERSION 1.6.3 CHANGES +------------------------------------------------------------------------ + * Bug fixes + * Redo image resize if problem occurred + * Grab title from image by default + * New German language file by alfalive + * Preview of watermarking +------------------------------------------------------------------------ +END VERSION 1.6.3 CHANGES +------------------------------------------------------------------------ + +------------------------------------------------------------------------ +Version 1.6.2 Change List +Release Date: 09/03/2009 +------------------------------------------------------------------------ +BEGIN VERSION 1.6.2 CHANGES +------------------------------------------------------------------------ + * Added widget for user's latest photos + * Added notifications to a user if that user is tagged in a photo + * Fixed some issues with tagging people in albums that belong to a closed group + * Added a test page for ImageMagick commandline + * Began restructuring the code for future capabilities + * Many more bug fixes and tweaks +------------------------------------------------------------------------ +END VERSION 1.6.2 CHANGES +------------------------------------------------------------------------ + + +------------------------------------------------------------------------ +Version 1.6.1 Change List +Release Date: 08/04/2009 +------------------------------------------------------------------------ +BEGIN VERSION 1.6.1 CHANGES +------------------------------------------------------------------------ + * Fixed css bug that caused problems with tagging + * Added Spanish language file from mylamilagros +------------------------------------------------------------------------ +END VERSION 1.6.1 CHANGES +------------------------------------------------------------------------ + + +------------------------------------------------------------------------ +Version 1.6.0 Change List +Final Release Date: 08/02/2009 +Beta 4 Release Date: 07/17/2009 +Beta 3 Release Date: 07/16/2009 +Beta 2 Release Date: 07/10/2009 +Beta 1 Release Date: 06/30/2009 +Contributors: + * Cash Costello + * Greg Froese + * tagging based on code by Pedro Prez + * RSS improvements by Torsten Wesolek + * language files submitted by Toto and Susan Tsairi +------------------------------------------------------------------------ +BEGIN VERSION 1.6.0 CHANGES +------------------------------------------------------------------------ + * Photo tagging + * View counter + * EXIF view + * ImageMagick support + * Extensive admin settings + * Improved CSS + * Image ratings + * Upload quotas + * Better album RSS feed + * better almost everything +------------------------------------------------------------------------ +END VERSION 1.6.0 CHANGES +------------------------------------------------------------------------ + + +------------------------------------------------------------------------ +Version 1.5.1 Change List +Release Date: 03/29/2009 +Contributors: + * Gabriel Monge-Franco (http://gabriel.mongefranco.com) + * Cash Costello + * VeniVidiVinco (http://community.elgg.org/pg/profile/VeniVidiVinco) +------------------------------------------------------------------------ +BEGIN VERSION 1.5.1 CHANGES +------------------------------------------------------------------------ +* Updated Turkish language file +* Fixed permissions bug on all content caused by group override +* Added back the create album button to widgets +------------------------------------------------------------------------ +END VERSION 1.5.1 CHANGES +------------------------------------------------------------------------ + + +------------------------------------------------------------------------ +Version 1.5 Change List +Release Date: 03/28/2009 +Contributors: + * Gabriel Monge-Franco (http://gabriel.mongefranco.com) + * Cash Costello + * alfalive (http://community.elgg.org/pg/profile/alfalive) + * VeniVidiVinco (http://community.elgg.org/pg/profile/VeniVidiVinco) + +Also thank you to those who tested the code in svn and provided feedback +------------------------------------------------------------------------ +BEGIN VERSION 1.5 CHANGES +------------------------------------------------------------------------ +* Fixed submenus on sidebar of album pages to make them consistent +* Fixed display issues for Elgg 1.5 +* Using default site access now +* Pushing new album creation to river +* Fixed German language file +* Added Turkish +* Added notifications for new album creation +* Rewrote most of the page handlers to make cleaner +* Fixed the access level bug on images +* Cleaned up css +* Fixed the group access bug on albums +------------------------------------------------------------------------ +END VERSION 1.5 CHANGES +------------------------------------------------------------------------ + + + +------------------------------------------------------------------------ +Version 1.08.2 Change List +Release Date: 02/13/2008 +Contributors: + * Gabriel Monge-Franco (http://gabriel.mongefranco.com) +------------------------------------------------------------------------ +BEGIN VERSION 1.08.2 CHANGES +------------------------------------------------------------------------ +* Fixed bug introduced in v1.08.1 that broke the picture upload (thanks to Karsten Schulze). +* Fixed empty variables in several files that were supposed to send the user back to the previous page, but didn't. +* Cleaned up change log (contributions.txt). +* Finally fixed the Polish language file!!! Yay!! :) + +* TODO: Work around large image (high resolution) limit when creating thumbnails (an Elgg limitation... can probably be fixed by using PHP GD functions directly or ImageMagic if available) + - The problem is with get_resized_image_from_existing_file(). Submitted a ticket to the Elgg tracking bug system. + - Edit actions/upload.php when done. There is a dirty hack in place for now that needs to be removed once the above bug is fixed. +* TODO: disable public by default (input/accessRead.php) -- add setting to admin page that lets the site admin decide whether pictures can be public or not. +* TODO: allow group members to add pictures to group photo albums +* TODO: implement photo anotations +* TODO: look into replacing individual image views with lightbox2 or jQuery lightbox album views. +* TODO: create a new widget to show pictures (in slideshow) in a user's profile. +* TODO: add settings for group albums so that the group owner can select the number of albums to show. +* TODO: implement a way to move pictures from one album to another (should be pretty easy). +* TODO: add an "Add Photos" option to the user widget similar to the one in the group widget. +* TODO: implement automagic file resizing to meet the admin's maximum resolution and file size. + +* OF NOTE: It is currently not possible to allow group members to edit an album created by another group member. This is a bug with group permissions and it will probably not be fixed until [at least] Elgg v1.5 comes out. +------------------------------------------------------------------------ +END VERSION 1.08.2 CHANGES +------------------------------------------------------------------------ + + +------------------------------------------------------------------------ +Version 1.08.1 Change List +Release Date: 02/13/2008 +Contributors: + * Gabriel Monge-Franco (http://gabriel.mongefranco.com) + * LKLaRose (http://community.elgg.org/pg/profile/lauren) + * Webgalli (http://community.elgg.org/pg/profile/webgalli) + * Karsten Schulze (http://ks.frinx.eu) + * Cash (http://community.elgg.org/pg/profile/costelloc) +------------------------------------------------------------------------ +BEGIN VERSION 1.08.1 CHANGES +------------------------------------------------------------------------ +* Fixed bug introduced in v1.08 that caused fake files to be created during thumbnail creation (thanks to Karsten Schulze). +* Reverted to old directory structure that saves pictures to /image/ALBUMGUID/picGUID (v1.08 saved to /image/ALBUMGUID__picGUID, thus keeping everything in one folder). +* Album directory is now deleted when the album is deleted (along with every picture inside of the album). +* Reverted thumbnail and small thumbnail to use picture cropping instead of scaling, so that sites that already use Tidypics can keep a consisting look and feel. +* Completed River integration by moving album and image directories to an "object" sub-directory (thanks to LKLaRose). +* Added status messages/graphics to give the user some feedback. +* Fixed bug in profile widget whereby the selected number of albums had no effect (thanks to @Webgalli and @cheltenham). +* Fixed bug introduced in v1.06 that prevented anonymous users from viewing a user's album (thanks to Karsten Schulze). +* Fixed more language file bugs (thanks to Karsten Schulze). +* Administrators can now set a file size limit from the plugin configuration (it has to be in Kilobytes). + +* JUST PLAIN WEIRD: Fixed Polish language file (thanks to @Vazco, Ian Medlock and Brett Profitt) and saved as UTF8 without BOM. However, it still doesn't work. Can somebody try saving it on a Polish box for me? :) + +* TODO: fix Polish language file -- it seems to break the whole Elgg site! Maybe it needs to use HTML codes in place of international characters? +* TODO: Work around large image (high resolution) limit when creating thumbnails (an Elgg limitation... can probably be fixed by using PHP GD functions directly or ImageMagic if available) + - The problem is with get_resized_image_from_existing_file(). Submitted a ticket to the Elgg tracking bug system. + - Edit actions/upload.php when done. There is a dirty hack in place for now that needs to be removed once the above bug is fixed. +* TODO: disable public by default (input/accessRead.php) -- add setting to admin page that lets the site admin decide whether pictures can be public or not. +* TODO: allow group members to add pictures to group photo albums +* TODO: implement photo anotations +* TODO: look into replacing individual image views with lightbox2 or jQuery lightbox album views. +* TODO: create a new widget to show pictures (in slideshow) in a user's profile. +* TODO: add settings for group albums so that the group owner can select the number of albums to show. +* TODO: implement a way to move pictures from one album to another (should be pretty easy). + +* OF NOTE: It is currently not possible to allow group members to edit an album created by another group member. This is a bug with group permissions and it will probably not be fixed until [at least] Elgg v1.5 comes out. +------------------------------------------------------------------------ +END VERSION 1.08.1 CHANGES +------------------------------------------------------------------------ + + +------------------------------------------------------------------------ +Version 1.08 Change List +Release Date: 02/08/2008 +Contributors: + * Gabriel Monge-Franco (http://gabriel.mongefranco.com) +------------------------------------------------------------------------ +BEGIN VERSION 1.08 CHANGES +------------------------------------------------------------------------ +* Merged most (safe) changes made by other contributors in v1.07. + - Did not include SWFuploader or JQuery due to the number of bugs reported. +* Changed ugly "new album" picture into something better looking. +* Fixed bug whereby image objects were deleted from the database, but they physical files remained on the server. + - Since deleting directories was not possible without the use of unsafe file operations, albums no longer create new directories. Instead, all pictures are saved as /image/ALBUMGUID__picturename. +* Fixed some bugs in the English, Spanish and German language files and added missing error messages. +* Thumbnails now display the default error image (same as new album) when the requested image cannot be found. +* Fixed a bug in the multi-edit form that did not allow image titles to be saved. +* Removed some customizations made to edit.php action in v1.07 since they removed the ability to add titles to images. +* Fixed bug introduced in v1.07 that prevented images from being set as album covers. +* Fixed miscellaneous bugs in group albums widget. +* Removed jQuery for now since it was making the albums too slow. In the future, we should look into replacing individual image views with lightbox2 or jQuery lightbox album views. + + +* TODO: fix Polish language file -- it seems to break the whole Elgg site! Maybe it needs to use HTML codes in place of international characters? +* TODO: Work around 0.9MB source file size limit when creating thumbnails (an Elgg limitation... can probably be fixed by using PHP GD functions directly) + - The problem is with get_resized_image_from_existing_file(). Submitted a ticket to the Elgg tracking bug system. + - Edit actions/upload.php when done. There is a dirty hack in place for now that needs to be removed once the above bug is fixed. +* TODO: disable public by default (input/accessRead.php) -- add setting to admin page that lets the site admin decide whether pictures can be public or not. +* TODO: allow group members to add pictures to group photo albums +* TODO: implement photo anotations +* TODO: look into replacing individual image views with lightbox2 or jQuery lightbox album views. + +* OF NOTE: It is currently not possible to allow group members to edit an album created by another group member. This is a bug with group permissions and it will probably not be fixed until [at least] Elgg v1.5 comes out. +------------------------------------------------------------------------ +END VERSION 1.08 CHANGES +------------------------------------------------------------------------ + + +------------------------------------------------------------------------ +Version 1.07 Change List +Release Date: 02/03/2008 +Contributors: + * vazco (http://community.elgg.org/pg/profile/vazco) + * simophin (http://community.elgg.org/pg/profile/simophin) +------------------------------------------------------------------------ +BEGIN VERSION 1.07 CHANGES +------------------------------------------------------------------------ +* About 10 missing translations added +* Translated to polish +* When no album is present, user can add a new album straight from the widget if he has the required rights +* Added some missing <p></p> +* Changed some <? to <?php +* Unauthorized album edit taken care of +* Added jQuery Lightbox support, but commented out just in case someone won't want to use it (there may be some problems with the lightbox, since I'm not using it myself and I didn't test it) +------------------------------------------------------------------------ +END VERSION 1.07 CHANGES +------------------------------------------------------------------------ + + +------------------------------------------------------------------------ +Version 1.06 Change List +Release Date: 02/03/2008 +Contributors: + * Gabriel Monge-Franco (http://gabriel.mongefranco.com) +------------------------------------------------------------------------ +BEGIN VERSION 1.06 CHANGES +------------------------------------------------------------------------ +* Forward all non-logged in users to World (public) pictures. This fixes a bug in which anonymous users would see a list of pictures titled, "'s pictures" (without a name). +* Forward requests to "owned" without an user ID to "owned/userid" when a user is logged in. This fixes a bug in which all users would see a list of pictures titled, "'s pictures" (without a name). +* Replaced several hard-coded strings to elgg_echo() functions so they can be translated. +* Re-enabled title entry in picture editing. Titles are only optional, so there is no reason to hide them, especially if some users may find them useful. Moreover, lack of image titles makes list views awkward. +* Fixed multi-picture editing bug in which editing was disabled after uploading multiple pictures. +* Fixed several tags not conforming to standard PHP opening tags. +* Fixed some bugs in the English language file. +* Added Spanish and German translations (if you speak German, please double-check the language file!!!). +* Added a download link at the bottom of each picture to download the original file. +* Updated some icons and created missing ones. + +* TODO: disable public by default (input/accessRead.php) -- add setting to admin page that lets the site admin decide whether pictures can be public or not. +* TODO: change ugly "new album" picture into something better looking. +* TODO: re-organize files to clean up the plug-in directory (e.g., move world.php to views/default) +* TODO: Fix bug whereby image objects are deleted from the database, but the physical files remain on the server. The path can be found with $file->getFilename(), but would it be safe to execute shell commands directly??? +------------------------------------------------------------------------ +END VERSION 1.06 CHANGES +------------------------------------------------------------------------ + diff --git a/plugins/tidypics/docs/configure_server.txt b/plugins/tidypics/docs/configure_server.txt new file mode 100644 index 0000000000000000000000000000000000000000..32fb5d86ea67af65f7a2823447b308726c0f1417 --- /dev/null +++ b/plugins/tidypics/docs/configure_server.txt @@ -0,0 +1,55 @@ +Server Configuration +----------------------------------- + +Run your server analysis located in the Tidypics Administration section and +then read through this document. + +If you are experiencing errors, please check your server error log. Tidypics +writes warnings for most upload related problems. You will see something +along these lines: "Tidypics warning: user exceeded post limit on image upload" + + + +GD: Elgg requires GD for image resizing. Tidypics uses GD by default for +resizing. There are two versions GD and GD2. It generally does not matter +which one you are using and it isn't always apparent which one you are +running anyway. + +ImageMagick: A significantly better image library than GD. There is a command-line +version that is commonly available on servers and a PHP extension call imagick that +you can install on your server (if you have control of your server). + +exec: Calls to ImageMagick command-line utilities like convert require that +exec() be available. On some servers it will be disabled for security reasons. + +Memory Available to PHP: The amount of RAM available to a single PHP +process. This can have an effect on how large an image you can resize +(especially if you are running Tidypics with GD). The best place to +change it is .htaccess. + +Memory Used to Load This Page: This gives you a baseline of how much +memory is being used to load the Elgg framework and plugins. + +Max File Upload Size: The largest file that can be uploaded. You can +adjust this in .htaccess. + +Max Post Size: The largest amount of data that can be submitted. For +Tidypics, this affects how many large images can be uploaded in a +single upload. If this is exceeded, nothing is uploaded and the +user gets an error message. It can be adjusted in .htaccess. + +Max Input Time: This is the amount of time PHP will wait for an +upload to finish. Your users may experience failures if they are +uploading large images on a poor connection or if your server +does not have a lot of bandwidth. + +Max Execution Time: The longest time a PHP script can run on your +server. If a user uploads many large images, the resize code may take +a long time to complete and will be stopped by PHP. If you are seeing +problems with this, you probably have a slow server. + +GD imagejpeg: jpeg resizing with GD + +GD imagegif: gif resizing with GD + +GD imagepng: png resizing with GD \ No newline at end of file diff --git a/plugins/tidypics/docs/css_guide.txt b/plugins/tidypics/docs/css_guide.txt new file mode 100644 index 0000000000000000000000000000000000000000..9663cad1aaeefcad95d2afd3ad4ae00920367444 --- /dev/null +++ b/plugins/tidypics/docs/css_guide.txt @@ -0,0 +1,87 @@ +Views: +----------------- +all albums view +album view +image view +upload view + + +CSS elements: +------------------------- +#tidypics_wrapper - wrapper on image view + +#tidypics_breadcrumbs - breadcrumbs on image and album views + +#tidypics_desc - description/caption in image and album views + +.tidypics_info - holds metadata about image/album like tags + +#tidypics_controls - image view controls (download, start tagging, etc.) + +.tidypics_album_images - border around images - needs work + +#tidypics_image_nav - back and next nav controls in image view + +#tidypics_image_full - not used + +#tidypics_image_wrapper - margins for image in image view + +#tidypics_image - frame + +.tidypics_album_cover - all albums view and river images + +.tidypics_album_widget_single_item + +.tidypics_album_gallery_item + + +/* ------ tidypics widget view ------ */ + +#tidypics_album_widget_container + +.tidypics_album_widget_timestamp + +/* --------- image upload/edit forms ------------ */ + +#tidpics_image_upload_list + +.tidypics_edit_image_container + +.tidypics_edit_images + +.tidypics_image_info + + +/* ---- tidypics group css ----- */ + +#group_albums_widget + + +/* --------- tidypics river items ------------ */ + +.river_object_image_create + +.river_object_album_create + +.river_object_image_comment + +.river_object_album_comment + +/* ----------- tagging ---------------- */ +#tidypics_tag_instructions + +#tidypics_tag_instruct_text + +#tidypics_tag_instruct_button_div + +#tidypics_tag_instruct_button + +#tidypics_tag_menu + +#tidypics_delete_tag_menu + +.tidypics_tag + +.tidypics_tag_text + +#tidypics_phototags_list diff --git a/plugins/tidypics/docs/extending_tidypics.txt b/plugins/tidypics/docs/extending_tidypics.txt new file mode 100644 index 0000000000000000000000000000000000000000..55e6b5dd547f0fbab14b8808cf96271075dad4a5 --- /dev/null +++ b/plugins/tidypics/docs/extending_tidypics.txt @@ -0,0 +1,39 @@ +Extending Tidypics +----------------------------------- + +*** DISPLAYING THE LATEST PHOTOS *** +In tidypics/lib/tidypics.php, there is a function tp_get_latest_photos(). +It can be used to display the site-wide latest photos or an individual +user's latest photos. The documentation explains how you could use that +function to display the latest photos on your front page if you are using +the custom front page tutorial plugin from Curverider. + + +*** MAKING TIDYPICS MATCH YOUR THEME *** +Please check the css guide found in this directory. This will list the +different css elements and where they are used. + + +*** TIDYPICS EVENTS *** +1. album created: 'add', 'tp_album' +2. album updated: 'update', 'tp_album' +3. album deleted: 'delete', 'tp_album' +4. photos uploaded: 'upload', 'tp_album' - triggered after a set have been uploaded and resized +5. photo uploaded: 'upload', 'tp_image' - triggered after each image is resized +6. photo edited: 'update', 'tp_image' +7. photo deleted: 'delete', 'tp_image' + +*** TIDYPICS PLUGIN HOOKS *** +1. album slideshow: 'tp_slideshow', 'album' - return false to not have a slideshow, otherwise return link to slideshow +2. watermark - return false to prevent default watermark + 'tp_watermark', 'gd' + 'tp_watermark', 'imagick' + 'tp_watermark', 'imagemagick' +3. image link: 'tp_image_link', 'image' - return false for no link or a url otherwise - params passed to this will porbably change in 1.7 + + +*** IMAGE MENU EXTENSIONS *** +Below an image is a div called tidypics_controls. By default it contains controls +like tagging or downloading an image. You can change what is shown there by overridding +or extending the tidypics/image_menu view. + diff --git a/plugins/tidypics/fonts/LiberationSerif-Regular.ttf b/plugins/tidypics/fonts/LiberationSerif-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1dd4aaa92b18c326a2737205ca519c5a2f11b3ea Binary files /dev/null and b/plugins/tidypics/fonts/LiberationSerif-Regular.ttf differ diff --git a/plugins/tidypics/fonts/License.txt b/plugins/tidypics/fonts/License.txt new file mode 100644 index 0000000000000000000000000000000000000000..e972b52de3e042189eeaf781fb1a7d6875dd880e --- /dev/null +++ b/plugins/tidypics/fonts/License.txt @@ -0,0 +1,13 @@ +LICENSE AGREEMENT AND LIMITED PRODUCT WARRANTY +LIBERATION FONT SOFTWARE + +This agreement governs the use of the Software and any updates to the Software, regardless of the delivery mechanism. Subject to the following terms, Red Hat, Inc. ("Red Hat") grants to the user ("Client") a license to this work pursuant to the GNU General Public License v.2 with the exceptions set forth below and such other terms as our set forth in this End User License Agreement. + + 1.The Software and License Exception. LIBERATION font software (the "Software") consists of TrueType-OpenType formatted font software for rendering LIBERATION typefaces in sans serif, serif, and monospaced character styles. You are licensed to use, modify, copy, and distribute the Software pursuant to the GNU General Public License v.2 with the following exceptions: +(a)As a special exception, if you create a document which uses this font, and embed this font or unaltered portions of this font into the document, this font does not by itself cause the resulting document to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the document might be covered by the GNU General Public License. If you modify this font, you may extend this exception to your version of the font, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. +(b)As a further exception, any distribution of the object code of the Software in a physical product must provide you the right to access and modify the source code for the Software and to reinstall that modified version of the Software in object code form on the same physical product on which you received it. + 2.Intellectual Property Rights. The Software and each of its components, including the source code, documentation, appearance, structure and organization are owned by Red Hat and others and are protected under copyright and other laws. Title to the Software and any component, or to any copy, modification, or merged portion shall remain with the aforementioned, subject to the applicable license. The "LIBERATION" trademark is a trademark of Red Hat, Inc. in the U.S. and other countries. This agreement does not permit Client to distribute modified versions of the Software using Red Hat's trademarks. If Client makes a redistribution of a modified version of the Software, then Client must modify the files names to remove any reference to the Red Hat trademarks and must not use the Red Hat trademarks in any way to reference or promote the modified Software. + 3.Limited Warranty. To the maximum extent permitted under applicable law, the Software is provided and licensed "as is" without warranty of any kind, expressed or implied, including the implied warranties of merchantability, non-infringement or fitness for a particular purpose. Red Hat does not warrant that the functions contained in the Software will meet Client's requirements or that the operation of the Software will be entirely error free or appear precisely as described in the accompanying documentation. + 4.Limitation of Remedies and Liability. To the maximum extent permitted by applicable law, Red Hat or any Red Hat authorized dealer will not be liable to Client for any incidental or consequential damages, including lost profits or lost savings arising out of the use or inability to use the Software, even if Red Hat or such dealer has been advised of the possibility of such damages. + 5.General. If any provision of this agreement is held to be unenforceable, that shall not affect the enforceability of the remaining provisions. This agreement shall be governed by the laws of the State of North Carolina and of the United States, without regard to any conflict of laws provisions, except that the United Nations Convention on the International Sale of Goods shall not apply. +Copyright © 2007 Red Hat, Inc. All rights reserved. LIBERATION is a trademark of Red Hat, Inc. diff --git a/plugins/tidypics/graphics/empty_album.png b/plugins/tidypics/graphics/empty_album.png new file mode 100644 index 0000000000000000000000000000000000000000..0c041d0a27664ebd707fceff4b8bf732ea9ad7c4 Binary files /dev/null and b/plugins/tidypics/graphics/empty_album.png differ diff --git a/plugins/tidypics/graphics/icons/album.gif b/plugins/tidypics/graphics/icons/album.gif new file mode 100644 index 0000000000000000000000000000000000000000..73ce91356fea9b68b84500b5dbe46a04194a7126 Binary files /dev/null and b/plugins/tidypics/graphics/icons/album.gif differ diff --git a/plugins/tidypics/graphics/icons/general.jpg b/plugins/tidypics/graphics/icons/general.jpg new file mode 100644 index 0000000000000000000000000000000000000000..23494eff2f351adf9030ccf372e5eb24b31b584b Binary files /dev/null and b/plugins/tidypics/graphics/icons/general.jpg differ diff --git a/plugins/tidypics/graphics/icons/river_icon_album.gif b/plugins/tidypics/graphics/icons/river_icon_album.gif new file mode 100644 index 0000000000000000000000000000000000000000..e1bbfedaa6bde840c4ba50238fa20483916d26e8 Binary files /dev/null and b/plugins/tidypics/graphics/icons/river_icon_album.gif differ diff --git a/plugins/tidypics/graphics/icons/river_icon_image.gif b/plugins/tidypics/graphics/icons/river_icon_image.gif new file mode 100644 index 0000000000000000000000000000000000000000..cf391898e2a56a26960713b603da44eb4c30f0a7 Binary files /dev/null and b/plugins/tidypics/graphics/icons/river_icon_image.gif differ diff --git a/plugins/tidypics/graphics/icons/river_icon_tag.gif b/plugins/tidypics/graphics/icons/river_icon_tag.gif new file mode 100644 index 0000000000000000000000000000000000000000..510696147efd1c7eb5d4ffd4cb2fe2e984b176b1 Binary files /dev/null and b/plugins/tidypics/graphics/icons/river_icon_tag.gif differ diff --git a/plugins/tidypics/graphics/image_error_large.png b/plugins/tidypics/graphics/image_error_large.png new file mode 100644 index 0000000000000000000000000000000000000000..4316f459df631b5fa2f76081d362dfa064c20d7d Binary files /dev/null and b/plugins/tidypics/graphics/image_error_large.png differ diff --git a/plugins/tidypics/graphics/image_error_small.png b/plugins/tidypics/graphics/image_error_small.png new file mode 100644 index 0000000000000000000000000000000000000000..2f814fd81bc50a7a5539cefee325eaf4bece6c6f Binary files /dev/null and b/plugins/tidypics/graphics/image_error_small.png differ diff --git a/plugins/tidypics/graphics/image_error_thumb.png b/plugins/tidypics/graphics/image_error_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..0eeb797dc7cd2579ebd13c922e622d7fba3e0194 Binary files /dev/null and b/plugins/tidypics/graphics/image_error_thumb.png differ diff --git a/plugins/tidypics/graphics/loader.gif b/plugins/tidypics/graphics/loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..7ac990cf04f2323f9723518bfd72ce102222cefa Binary files /dev/null and b/plugins/tidypics/graphics/loader.gif differ diff --git a/plugins/tidypics/graphics/spacer.gif b/plugins/tidypics/graphics/spacer.gif new file mode 100644 index 0000000000000000000000000000000000000000..e565824aafafe632011b281cba976baf8b3ba89a Binary files /dev/null and b/plugins/tidypics/graphics/spacer.gif differ diff --git a/plugins/tidypics/languages/da.php b/plugins/tidypics/languages/da.php new file mode 100644 index 0000000000000000000000000000000000000000..b27639772e209eb26e56c319e8951a077846df5b --- /dev/null +++ b/plugins/tidypics/languages/da.php @@ -0,0 +1,195 @@ +<?php +/** +* Elgg tidypics plugin danish language pack +* Beta Version 0.8.1 +* +*/ + + + $danish = array( + + // Menu items and titles + + 'image' => "Billede", + 'images' => "Billeder", + 'caption' => "Beskrivelse", + 'photos' => "Fotos", + 'images:upload' => "Upload fotos", + 'images:multiupload' => "Flash Multi-Upload værktøj", + 'images:multiupload:todo' => "Vælg et eller flere billeder til upload!", + 'album' => "Fotoalbum", + 'albums' => "Fotoalbums", + 'album:slideshow' => "Se slideshow", + 'album:yours' => "Dine Fotoalbums", + 'album:yours:friends' => "Dine venners fotoalbums", + 'album:user' => "%s's Fotoalbums", + 'album:friends' => "%s's venners fotoalbum", + 'album:all' => "Alle Fotoalbums", + 'album:group' => "Gruppe-Fotoalbum", + 'item:object:image' => "Fotos", + 'item:object:album' => "Album", + 'tidypics:uploading:images' => "Billederne er uploadet", + 'tidypics:enablephotos' => 'Skift gruppealbum', + 'tidypics:editprops' => 'Rediger billede', + 'tidypics:mostcommented' => 'Mest kommenterede', + 'tidypics:mostcommentedthismonth' => 'Mest kommenterede i denne måned', + 'tidypics:mostcommentedtoday' => 'Mest kommenterede i dag', + 'tidypics:mostviewed' => 'Mest besøgte billeder', + 'tidypics:mostvieweddashboard' => 'Mest besøgte instrumentpanel', + 'tidypics:mostviewedthisyear' => 'Mest besøgte i år', + 'tidypics:mostviewedthismonth' => 'Mest besøgte i denne måned', + 'tidypics:mostviewedlastmonth' => 'Mest besøgte sidste måned', + 'tidypics:mostviewedtoday' => 'Set flest gange i dag', + 'tidypics:recentlyviewed' => 'Senest viste billeder', + 'tidypics:recentlycommented' => 'Senest kommenterede billeder', + 'tidypics:mostrecent' => 'Nyeste billeder ifællesskabet', + 'tidypics:yourmostviewed' => 'Dine mest sete', + 'tidypics:yourmostrecent' => 'Sidst uploaded', + 'tidypics:friendmostviewed' => "%s's mest sete", + 'tidypics:friendmostrecent' => "%s's seneste billeder ", + 'tidypics:highestrated' => "Højest bedømte billeder", + 'tidypics:viewsbyowner' => "Visninger: %s af %s medlemmer (ikke inklusive dig selv)", + 'tidypics:viewsbyothers' => "Visninger: %s (%s af dig)", + 'tidypics:administration' => 'Tidypics administration', + 'tidypics:stats' => 'Statistik', + + //settings + 'tidypics:settings' => 'Indstillinger', + 'tidypics:admin:instructions' => 'Dette er de centrale Tidypics indstillinger. Tilpas dem til din opsætning og klik derefter på Gem.', + 'tidypics:settings:image_lib' => "Foto arkiv: ", + 'tidypics:settings:download_link' => "Vis download-link", + 'tidypics:settings:tagging' => "Tillad fotolinks", + 'tidypics:settings:photo_ratings' => "Tillad karakterergivning af foto (kræver plugin af Miguel Montes eller andet kompatibelt plugin)", + 'tidypics:settings:exif' => "Vis EXIF data", + 'tidypics:settings:view_count' => "Vis tæller", + 'tidypics:settings:grp_perm_override' => "Giv gruppens medlemmer fuld adgang til gruppe-album", + 'tidypics:settings:maxfilesize' => "Maksimal billedstørrelse i megabytes (MB):", + 'tidypics:settings:quota' => "Tildelt plads til brugere / grupper (MB) (0 = Ingen plads)", + 'tidypics:settings:watermark' => "Indtast teksten for vandmærke - ImageMagick cmdline skal vælges for billedbiblioteket", + 'tidypics:settings:im_path' => "Angiv stien til ImageMagick kommandoer (som slutter med et Slash/)", + 'tidypics:settings:img_river_view' => "Hvor mange poster i aktivitetslisten for hvert parti af uploadede billeder", + 'tidypics:settings:album_river_view' => "Vis albumcover eller et sæt af fotos til nye album", + 'tidypics:settings:largesize' => "Størrelse på billede", + 'tidypics:settings:smallsize' => "Tumbnailstørrelse på album", + 'tidypics:settings:thumbsize' => "Thumbnailstørrelse på billede", + + + //actions + + 'album:create' => "Skab album", + 'album:add' => "Tilføj nyt album", + 'album:addpix' => "Tilføj fotos", + 'album:edit' => "Rediger album", + 'album:delete' => "Slet album", + + 'image:edit' => "Rediger billede", + 'image:delete' => "Slet billede", + 'image:download' => "Download billede", + + //forms + + 'album:title' => "Titel", + 'album:desc' => "Beskrivelse", + 'album:tags' => "Nøgleord", + 'album:cover' => "Billedet skal bruges som albumcover", + 'tidypics:quota' => "Plads:", + + //views + + 'image:total' => "Billeder i album:", + 'image:by' => "Billede tilføjet af", + 'album:by' => "Album oprettet af:", + 'album:created:on' => "Oprettet", + 'image:none' => "Ingen billeder tilføjet.", + 'image:back' => "Forrige", + 'image:next' => "Næste", + + // tagging + 'tidypics:taginstruct' => 'Vælg et område på billedet, som du ønsker at linke', + 'tidypics:deltag_title' => 'Vælg at slette links', + 'tidypics:finish_tagging' => 'Annuller', + 'tidypics:tagthisphoto' => 'Tilføj link til foto', + 'tidypics:deletetag' => 'Slet foto link', + 'tidypics:actiontag' => 'Link', + 'tidypics:actiondelete' => 'Slet', + 'tidypics:actioncancel' => 'Annuller', + 'tidypics:inthisphoto' => 'Links i billedet', + 'tidypics:usertag' => "Foto links til medlem %s", + 'tidypics:phototagging:success' => 'Foto link tilføjet', + 'tidypics:phototagging:error' => 'Uventet fejl ved linket', + 'tidypics:deletetag:success' => 'Udvalgte links er blevet fjernet', + + + //rss + 'tidypics:posted' => 'Billedet indstilles individuelt:', + + //widgets + + 'tidypics:widget:albums' => "Fotoalbum", + 'tidypics:widget:album_descr' => "Viser seneste album", + 'tidypics:widget:num_albums' => "Antal albums", + 'tidypics:widget:latest' => "Nyeste billeder", + 'tidypics:widget:latest_descr' => "Vis seneste billeder", + 'tidypics:widget:num_latest' => "Antal billeder", + 'album:more' => "Vis alle albums", + + //river + + //images + 'image:river:created' => "%s har tilføjet et billede %s i album %s", + 'image:river:item' => "et billede", + 'image:river:annotate' => "en kommentar til billedet", + + //albums + 'album:river:created' => "%s har tilføjet et nyt album", + 'album:river:group' => "i gruppen", + 'album:river:item' => "et album", + 'album:river:annotate' => "en kommentar til albummet", + + //notifications + 'tidypics:newalbum' => 'Nye Fotoalbum', + + + // Status messages + 'tidypics:upl_success' => "Billedet er uploadet med succes", + 'image:saved' => "Billedet blev gemt", + 'images:saved' => "Alle billeder er gemt", + 'image:deleted' => "Billedet blev slettet", + 'image:delete:confirm' => "Ønsker du at slette dette billede?", + + 'images:edited' => "Billedet er blevet opdateret", + 'album:edited' => "Albummet er blevet opdateret", + 'album:saved' => "Albummet blev gemt", + 'album:deleted' => "Albummet er blevet slettet", + 'album:delete:confirm' => "Ønsker du at slette dette album?", + 'album:created' => "Deres nye album er skabt", + 'tidypics:settings:save:ok' => 'Tidypics Indstillingerne er gemt', + 'tidypics:upgrade:success' => 'Tidypics blev opgraderet med succes', + + //Error messages + + 'tidypics:partialuploadfailure' => "Der opstod en fejl under uploadingen af billeder (%s af %s billeder)", + 'tidypics:completeuploadfailure' => "Upload af billede mislykkedes", + 'tidypics:exceedpostlimit' => "Alt for mange store billeder på én gang - forsøg evt. at overføre færre eller mindre billeder", + 'tidypics:noimages' => "Ingen billeder udvalgt til upload", + 'tidypics:image_mem' => "Billedet er for stort", + 'tidypics:image_pixels' => "Billedet har for mange pixels", + 'tidypics:unk_error' => "Ukendt fejl opstod under upload", + 'tidypics:save_error' => "Ukendt fejl opstod, da billedet skulle gemmes på serveren", + 'tidypics:not_image' => "Type af billede kan ikke genkendes", + 'image:deletefailed' => "Dit billede kunne ikke slettes", + 'image:downloadfailed' => "Fejl: Billedet er ikke tilgængeligt i øjeblikket", + 'tidypics:nosettings' => "Administratoren af webstedet, har ikke foretaget justeringer for fotoalbum", + 'tidypics:exceed_quota' => "Din tildelte plads er opbrugt!", + 'images:notedited' => "Ikke alle billeder er blevet opdateret", + + 'album:none' => "Ingen albums skabt endnu", + 'album:uploadfailed' => "Dit album kunne ikke gemmes", + 'album:deletefailed' => "Dit album kunne ikke slettes", + 'album:blank' => "Giv venligst dette album en titel samt beskrivelse", + + 'tidypics:upgrade:failed' => "Opgraderingen af Tidypics mislykkedes", + ); + + add_translation("da",$danish); +?> diff --git a/plugins/tidypics/languages/de.php b/plugins/tidypics/languages/de.php new file mode 100644 index 0000000000000000000000000000000000000000..7b014bc0d0e9ec60040feb3d2db523b3981fd34c --- /dev/null +++ b/plugins/tidypics/languages/de.php @@ -0,0 +1,227 @@ +<?php +/** +* Elgg tidypics plugin german language pack +* Beta Version 0.8.4 +* +*/ + + + $german = array( + // hack for core bug + 'untitled' => "Unbenannt", + + // Menu items and titles + + 'image' => "Bild", + 'images' => "Bilder", + 'caption' => "Beschreibung", + 'photos' => "Fotos", + 'images:upload' => "Fotos hochladen", + 'images:multiupload' => "Flash Multi-Upload Tool", + 'images:multiupload:todo' => "Ein oder mehrere Bilder zum Hochladen wählen!", + 'album' => "Fotoalbum", + 'albums' => "Fotoalben", + 'album:slideshow' => "Diashow ansehen", + 'album:yours' => "Deine Fotoalben", + 'album:yours:friends' => "Fotoalben deiner Freunde", + 'album:user' => "%s's Fotoalben", + 'album:friends' => "Fotoalben von %s's Freunden", + 'album:all' => "Alle Fotoalben", + 'album:group' => "Gruppen-Alben", + 'item:object:image' => "Fotos", + 'item:object:album' => "Alben", + 'tidypics:uploading:images' => "Die Bilder werden hochgeladen", + 'tidypics:enablephotos' => 'Schalte Gruppenalben frei', + 'tidypics:editprops' => 'Bild bearbeiten', + 'tidypics:mostcommented' => 'meist kommentierte', + 'tidypics:mostcommentedthismonth' => 'Meist kommentierte des Monats', + 'tidypics:mostcommentedtoday' => 'Meist kommentierte des Tages', + 'tidypics:mostviewed' => 'Meist gesehene Bilder', + 'tidypics:mostvieweddashboard' => 'Meist gesehene dashboard', + 'tidypics:mostviewedthisyear' => 'Meist gesehene des Jahres', + 'tidypics:mostviewedthismonth' => 'Meist gesehene des Monats', + 'tidypics:mostviewedlastmonth' => 'Meist gesehen im letzten Monat', + 'tidypics:mostviewedtoday' => 'Am häufigsten gezeigte des Tages', + 'tidypics:recentlyviewed' => 'Zuletzt angezeigt', + 'tidypics:recentlycommented' => 'Zuletzt kommentiert', + 'tidypics:mostrecent' => 'Community neue Bilder', + 'tidypics:yourmostviewed' => 'Deine meist gesehene', + 'tidypics:yourmostrecent' => 'Zuletzt hochgeladen', + 'tidypics:friendmostviewed' => "%s's meist gesehene", + 'tidypics:friendmostrecent' => "Zuletzt hochgeladen von %s", + 'tidypics:highestrated' => "Am höchsten bewertet", + 'tidypics:views' => "Zugriffe: %s", + 'tidypics:viewsbyowner' => "Zugriffe: %s von %s Mitglieder (du ausgeschlossen)", + 'tidypics:viewsbyothers' => "Zugriffe: %s (%s deine)", + 'tidypics:administration' => 'Tidypics Administration', + 'tidypics:stats' => 'Statitik', + + //settings + 'tidypics:settings' => 'Einstellungen', + 'tidypics:admin:instructions' => 'Das sind die Tidypics Einstellungen', + + 'tidypics:settings:image_lib' => "Image Library: ", + 'tidypics:settings:thumbnail' => "Thumbnail Creation", + 'tidypics:settings:download_link' => "Zeige Download-Link", + 'tidypics:settings:tagging' => "Erlaube Foto-Links", + 'tidypics:settings:photo_ratings' => "Erlaube Foto Bewertungen (benötigt rate plugin of Miguel Montes oder passendes)", + 'tidypics:settings:exif' => "Zeige EXIF data", + 'tidypics:settings:view_count' => "Zeige Zähler", + 'tidypics:settings:grp_perm_override' => "Erlaube den Gruppen-Mitgliedern unbeschränkten zugagn zur verwaltung von Gruppen-Alben", + 'tidypics:settings:maxfilesize' => "Maximale Bildgröße in Megabytes (MB):", + 'tidypics:settings:quota' => "Benutzer/Gruppen Speicherplatz in (MB) (0 = Kein Speicherplatz)", + 'tidypics:settings:watermark' => "Gib den Text für den Wasserzeichen ein - ImageMagick Cmdline muss ausgewählt sein für die Bildbibliothek", + + 'tidypics:settings:im_path' => "Gib den Pfad zu ImageMagick Befehle (mit abschließendem Slasch)", + 'tidypics:settings:img_river_view' => "Wie viele Einträge in der aktivitäten Liste beim Upload von mehreren Bildern", + 'tidypics:settings:album_river_view' => "Zeige Albumcover oder ein Set von Fotos für neuen Album", + 'tidypics:settings:largesize' => "Bild-Größe", + 'tidypics:settings:smallsize' => "Album-Tumbnail Bild-Größe", + 'tidypics:settings:thumbsize' => "Thumbnail Bild-Größe", + 'tidypics:settings:im_id' => "Bild ID", + + + //actions + + 'album:create' => "Album hinzufügen", + 'album:add' => "Neues Album hinzufügen", + 'album:addpix' => "Fotos hinzufügen", + 'album:edit' => "Album bearbeiten", + 'album:delete' => "Album löschen", + + 'image:edit' => "Bild bearbeiten", + 'image:delete' => "Bild löschen", + 'image:download' => "Bild herunterladen", + + //forms + + 'album:title' => "Titel", + 'album:desc' => "Beschreibung", + 'album:tags' => "Stichwörter", + 'album:cover' => "Das bild als Albumcover nutzen", + 'tidypics:quota' => "Speicherplatz:", + + //views + + 'image:total' => "Bilder im Album:", + 'image:by' => "Bild hinzugefügt von", + 'album:by' => "Album erstellt von:", + 'album:created:on' => "Erstellt", + 'image:none' => "Noch keine Bilder hinzugefügt.", + 'image:back' => "Vorheriges", + 'image:next' => "Nächstes", + + // tagging + 'tidypics:taginstruct' => 'Wähle ein Bereich auf dem Foto den du Verlinken willst', + 'tidypics:deltag_title' => 'Wähle zu löschende Links', + 'tidypics:finish_tagging' => 'Abbrechen', + 'tidypics:tagthisphoto' => 'Link zum Foto hinzufügen', + 'tidypics:deletetag' => 'Lösche Foto-Link', + 'tidypics:actiontag' => 'Link', + 'tidypics:actiondelete' => 'Löschen', + 'tidypics:actioncancel' => 'Abbrechen', + 'tidypics:inthisphoto' => 'Links in dem Foto', + 'tidypics:usertag' => "Foto verlinkt mit Mitglied %s", + 'tidypics:phototagging:success' => 'Foto-Link erfolgreich hinzugefügt', + 'tidypics:phototagging:error' => 'Unerwarteter Fehler beim verlinken', + 'tidypics:deletetag:success' => 'Ausgewählte Links wurden erfolgreich gelöscht', + + 'tidypics:tag:subject' => "Du wurdest in einem Foto verlinkt", + 'tidypics:tag:body' => "Du wurdest in diesem Foto verlinkt %s von %s. + +Das Foto kanns du hier sehen: %s", + + + //rss + 'tidypics:posted' => 'Das Bild eingestellt:', + + //widgets + + 'tidypics:widget:albums' => "Fotoalben", + 'tidypics:widget:album_descr' => "Zeige neuste Alben", + 'tidypics:widget:num_albums' => "Anzahl der Alben", + 'tidypics:widget:latest' => "Neuste Bilder", + 'tidypics:widget:latest_descr' => "Zeige neuste Bilder", + 'tidypics:widget:num_latest' => "Anzahl der Bilder", + 'album:more' => "Alle Alben ansehen", + + //river + + //images + 'image:river:created' => "%s hat ein Bild %s zum Album %s hinzugefügt", + 'image:river:item' => "ein Bild", + 'image:river:annotate' => "einen Kommentar zum Bild", + 'image:river:tagged' => "war im Foto verlinkt", + + //albums + 'album:river:created' => "%s hat ein neues Album erstellt", + 'album:river:group' => "in der Gruppe", + 'album:river:item' => "ein Album", + 'album:river:annotate' => "einen Kommentar zum Album", + + //notifications + 'tidypics:newalbum' => 'Neues Fotoalbum', + + + + // Status messages + 'tidypics:upl_success' => "Die Bilder sind erfolgreich hochgeladen", + 'image:saved' => "Das Bild wurde gespeichert", + 'images:saved' => "Alle Bilder sind gespeichert", + 'image:deleted' => "Das Bild wurde gelöscht", + 'image:delete:confirm' => "Willst du das Bild wirklich löschen?", + + 'images:edited' => "Das Bild wurde aktualisiert", + 'album:edited' => "Das Album wurde aktualisiert", + 'album:saved' => "Das Album wurde gespeichert", + 'album:deleted' => "Das Album wurde gelöscht", + 'album:delete:confirm' => "Willst du das Album wirklich löschen?", + 'album:created' => "Dein neues Album ist erstellt", + 'tidypics:settings:save:ok' => 'Tidypics Einstellungen erfolgreich gespeichert', + + + + + + + + + + + + 'tidypics:upgrade:success' => 'Upgrade von Tidypics erfolgreich', + + //Error messages + + 'tidypics:partialuploadfailure' => "Es sind Fehler beim Hochladen einiger Bilder aufgetreten (%s von %s Bildern)", + 'tidypics:completeuploadfailure' => "Bilder-Upload fehlgeschlagen", + 'tidypics:exceedpostlimit' => "Zuviele große Bilder auf einmal - versuche weniger oder kleinere Bilder hochzuladen", + + 'tidypics:noimages' => "Keine Bilder zum Upload ausgewählt", + 'tidypics:image_mem' => "Das Bild ist zu groß", + 'tidypics:image_pixels' => "Das Bild hat zuviele Pixel", + 'tidypics:unk_error' => "Unbekannte Fehler beim Upload ", + 'tidypics:save_error' => "Unbekanntes Fehler beim speichern des Bildes auf dem Server", + 'tidypics:not_image' => "Das Bild-Typ wurde nicht erkannt", + 'image:deletefailed' => "Dein Bild konnte nicht gelöscht werden", + 'image:downloadfailed' => "Fehler: Das Bild ist zur Zeit nicht verfügbar", + + + 'tidypics:nosettings' => "Admin dieser Seite hat keine Einstellungen für Fotoalben vorgenommen", + 'tidypics:exceed_quota' => "Dir zugewiesener Speicherplatz ist ausgeschöpft!", + + 'images:notedited' => "Nicht alle Bilder konnten erfolgreich upgedated werden", + + 'album:none' => "Bis jetzt keine Alben erstellt", + + 'album:uploadfailed' => "Dein Album konnte nicht gespeichert werden", + 'album:deletefailed' => "Dein Album konnte nicht gelöscht werden", + 'album:blank' => "Bitte gib diesem Album einen Titel und eine Beschreibung", + + + + 'tidypics:upgrade:failed' => "Upgrade von Tidypics gescheitert", + ); + + add_translation("de",$german); +?> diff --git a/plugins/tidypics/languages/en.php b/plugins/tidypics/languages/en.php new file mode 100644 index 0000000000000000000000000000000000000000..934c8ae5abe231214b30ea9d046625243e26b832 --- /dev/null +++ b/plugins/tidypics/languages/en.php @@ -0,0 +1,231 @@ +<?php + + $english = array( + // hack for core bug + 'untitled' => "untitled", + + // Menu items and titles + + 'image' => "Image", + 'images' => "Images", + 'caption' => "Caption", + 'photos' => "Photos", + 'images:upload' => "Upload Images", + 'images:multiupload' => "Flash Multi Upload Tool", + 'images:multiupload:todo' => "Choose one or more files for upload.", + 'album' => "Photo Album", + 'albums' => "Photo Albums", + 'album:slideshow' => "View slideshow", + 'album:yours' => "Your photo albums", + 'album:yours:friends' => "Your friends' photo albums", + 'album:user' => "%s's photo albums", + 'album:friends' => "%s's friends' photo albums", + 'album:all' => "All site photo albums", + 'album:group' => "Group albums", + 'item:object:image' => "Photos", + 'item:object:album' => "Albums", + 'tidypics:uploading:images' => "Please wait. Uploading images.", + 'tidypics:enablephotos' => 'Enable group photo albums', + 'tidypics:editprops' => 'Edit Image Properties', + 'tidypics:mostcommented' => 'Most commented images', + 'tidypics:mostcommentedthismonth' => 'Most commented this month', + 'tidypics:mostcommentedtoday' => 'Most commented today', + 'tidypics:mostviewed' => 'Most viewed images', + 'tidypics:mostvieweddashboard' => 'Most viewed dashboard', + 'tidypics:mostviewedthisyear' => 'Most viewed this year', + 'tidypics:mostviewedthismonth' => 'Most viewed this month', + 'tidypics:mostviewedlastmonth' => 'Most viewed last month', + 'tidypics:mostviewedtoday' => 'Most viewed today', + 'tidypics:recentlyviewed' => 'Recently viewed images', + 'tidypics:recentlycommented' => 'Recently commented images', + 'tidypics:mostrecent' => 'Most recent images', + 'tidypics:yourmostviewed' => 'Your most viewed images', + 'tidypics:yourmostrecent' => 'Your most recent images', + 'tidypics:friendmostviewed' => "%s's most viewed images", + 'tidypics:friendmostrecent' => "%s's most recent images", + 'tidypics:highestrated' => "Highest rated images", + 'tidypics:views' => "Views: %s", + 'tidypics:viewsbyowner' => "by %s users (not including you)", + 'tidypics:viewsbyothers' => "(%s by you)", + 'tidypics:administration' => 'Tidypics Administration', + 'tidypics:stats' => 'Stats', + 'tidypics:nophotosingroup' => 'This groups does not have any photos yet', + + 'flickr:setup' => 'Flickr Setup', + 'flickr:usernamesetup' => 'Please enter your Flickr username here:', + 'flickr:selectalbum' => 'Select album to import photos into', + 'flickr:albumdesc' => 'Album to import photos to:', + 'flickr:importmanager' => 'Photoset Import Manager', + 'flickr:desc' => 'Click on the set you wish to import into this site.<br />Copies of the photos will be made and stored on this site where they can be viewed and commented on.', + 'flickr:intro' => 'Flickr Integration allows you to import photos from your flickr account into this Elgg site. By entering your username and choosing an album to import into, you can begin the process. <br />When you have saved your username and album selection, click on the Import Flickr Photos link to the left to select which Flickr set you would like to import photos from.', + 'flickr:menusetup' => 'Flickr Setup', + 'flickr:menuimport' => 'Import Flickr Photos', + + //settings + 'tidypics:settings' => 'Settings', + 'tidypics:admin:instructions' => 'These are the core Tidypics settings. Change them for your setup and then click save.', + 'tidypics:settings:image_lib' => "Image Library", + 'tidypics:settings:thumbnail' => "Thumbnail Creation", + 'tidypics:settings:help' => "Help", + 'tidypics:settings:download_link' => "Show download link", + 'tidypics:settings:tagging' => "Enable photo tagging", + 'tidypics:settings:photo_ratings' => "Enable photo ratings (requires rate plugin of Miguel Montes or compatible)", + 'tidypics:settings:exif' => "Show EXIF data", + 'tidypics:settings:view_count' => "View counter", + 'tidypics:settings:grp_perm_override' => "Allow group members full access to group albums", + 'tidypics:settings:maxfilesize' => "Maximum image size in megabytes (MB):", + 'tidypics:settings:quota' => "User/Group Quota (MB) - 0 equals no quota", + 'tidypics:settings:watermark' => "Enter text to appear in the watermark", + 'tidypics:settings:im_path' => "Enter the path to your ImageMagick commands (with trailing slash)", + 'tidypics:settings:img_river_view' => "How many entries in activity river for each batch of uploaded images", + 'tidypics:settings:album_river_view' => "Show the album cover or a set of photos for new album", + 'tidypics:settings:largesize' => "Primary image size", + 'tidypics:settings:smallsize' => "Album view image size", + 'tidypics:settings:thumbsize' => "Thumbnail image size", + 'tidypics:settings:im_id' => "Image ID", + + 'tidypics:settings:heading:img_lib' => "Image Library Settings", + 'tidypics:settings:heading:main' => "Major Settings", + 'tidypics:settings:heading:river' => "Activity Integration Options", + 'tidypics:settings:heading:sizes' => "Thumbnail Size", + 'tidypics:settings:heading:groups' => "Group Settings", + + //actions + + 'album:create' => "Create new album", + 'album:add' => "Add Photo Album", + 'album:addpix' => "Add photos to album", + 'album:edit' => "Edit album", + 'album:delete' => "Delete album", + + 'image:edit' => "Edit image", + 'image:delete' => "Delete image", + 'image:download' => "Download image", + + //forms + + 'album:title' => "Title", + 'album:desc' => "Description", + 'album:tags' => "Tags", + 'album:cover' => "Make image album cover?", + 'tidypics:quota' => "Quota usage:", + + //views + + 'image:total' => "Images in album:", + 'image:by' => "Image added by", + 'album:by' => "Album created by", + 'album:created:on' => "Created", + 'image:none' => "No images have been added yet.", + 'image:back' => "Previous", + 'image:next' => "Next", + + // tagging + 'tidypics:taginstruct' => 'Select area that you want to tag', + 'tidypics:deltag_title' => 'Select tags to delete', + 'tidypics:finish_tagging' => 'Stop tagging', + 'tidypics:tagthisphoto' => 'Tag this photo', + 'tidypics:deletetag' => 'Delete a photo tag', + 'tidypics:actiontag' => 'Tag', + 'tidypics:actiondelete' => 'Delete', + 'tidypics:actioncancel' => 'Cancel', + 'tidypics:inthisphoto' => 'In this photo', + 'tidypics:usertag' => "Photos tagged with user %s", + 'tidypics:phototagging:success' => 'Photo tag was successfully added', + 'tidypics:phototagging:error' => 'Unexpected error occurred during tagging', + 'tidypics:deletetag:success' => 'Selected tags were successfully deleted', + + 'tidypics:tag:subject' => "You have been tagged in a photo", + 'tidypics:tag:body' => "You have been tagged in the photo %s by %s. + +The photo can be viewed here: %s", + + + //rss + 'tidypics:posted' => 'posted a photo:', + + //widgets + + 'tidypics:widget:albums' => "Photo Albums", + 'tidypics:widget:album_descr' => "Showcase your photo albums", + 'tidypics:widget:num_albums' => "Number of albums to display", + 'tidypics:widget:latest' => "Latest Photos", + 'tidypics:widget:latest_descr' => "Display your latest photos", + 'tidypics:widget:num_latest' => "Number of images to display", + 'album:more' => "View all albums", + + // river + + //images + 'image:river:created' => "%s added the photo %s to album %s", + 'image:river:item' => "an photo", + 'image:river:annotate' => "a comment on the photo", + 'image:river:tagged' => "was tagged in the photo", + + //albums + 'album:river:created' => "%s created a new photo album", + 'album:river:group' => "in the group", + 'album:river:item' => "an album", + 'album:river:annotate' => "a comment on the photo album", + + // notifications + 'tidypics:newalbum' => 'New photo album', + + + // Status messages + + 'tidypics:upl_success' => "Your images uploaded successfully.", + 'image:saved' => "Your image was successfully saved.", + 'images:saved' => "All images were successfully saved.", + 'image:deleted' => "Your image was successfully deleted.", + 'image:delete:confirm' => "Are you sure you want to delete this image?", + + 'images:edited' => "Your images were successfully updated.", + 'album:edited' => "Your album was successfully updated.", + 'album:saved' => "Your album was successfully saved.", + 'album:deleted' => "Your album was successfully deleted.", + 'album:delete:confirm' => "Are you sure you want to delete this album?", + 'album:created' => "Your new album has been created.", + 'tidypics:settings:save:ok' => 'Successfully saved the Tidypics plugin settings', + + 'tidypics:upgrade:success' => 'Upgrade of Tidypics a success', + + 'flickr:enterusername' => 'You must enter a username', + 'flickr:savedusername' => 'Successfully saved username of %s', + 'flickr:saveduserid' => 'Successfully saved userid of %s', + 'flickr:savedalbum' => 'Album saved - %s', + + //Error messages + + 'tidypics:baduploadform' => "There was an error with the upload form", + 'tidypics:partialuploadfailure' => "There were errors uploading some of the images (%s of %s images).", + 'tidypics:completeuploadfailure' => "Upload of images failed.", + 'tidypics:exceedpostlimit' => "Too many large images - try to upload fewer or smaller images.", + 'tidypics:noimages' => "No images were selected.", + 'tidypics:image_mem' => "Image is too large - too many bytes", + 'tidypics:image_pixels' => "Image has too many pixels", + 'tidypics:unk_error' => "Unknown upload error", + 'tidypics:save_error' => "Unknown error saving the image on server", + 'tidypics:not_image' => "This is not a recognized image type", + 'tidypics:deletefailed' => "Sorry. Deletion failed.", + 'tidypics:deleted' => "Successful deletion.", + 'image:downloadfailed' => "Sorry; this image is not available at this time.", + 'tidypics:nosettings' => "Admin of this site has not set photo album settings.", + 'tidypics:exceed_quota' => "You have exceeded the quota set by the administrator", + 'images:notedited' => "Not all images were successfully updated", + + 'album:none' => "No albums have been created yet.", + 'album:uploadfailed' => "Sorry; we could not save your album.", + 'album:deletefailed' => "Your album could not be deleted at this time.", + 'album:blank' => "Please give this album a title and description.", + + 'tidypics:upgrade:failed' => "The upgrade of Tidypics failed", + + 'flickr:errorusername' => 'Username %s not found on Flickr', + 'flickr:errorusername2' => 'You must enter a username', + 'flickr:errorimageimport' => 'This image has already been imported', + 'flickr:errornoalbum' => "No album selected. Please choose and save an album: %s" + ); + + add_translation("en",$english); +?> diff --git a/plugins/tidypics/languages/es.php b/plugins/tidypics/languages/es.php new file mode 100644 index 0000000000000000000000000000000000000000..1c9b580ef5831f989e6b51ccc99513ddf95399ca --- /dev/null +++ b/plugins/tidypics/languages/es.php @@ -0,0 +1,191 @@ +<?php +/**TRADUCIDO POR ALIX SILVA, CARLOS SILVA Y LA COMUNIDAD ELGG**/ + + $spanish = array( + // hack for core bug + 'untitled' => "sin titulo", + + // Menu items and titles + 'image' => "Imagen", + 'images' => "Imagenes", + 'caption' => "Título", + 'photos' => "Fotos", + 'images:upload' => "Cargar Imagenes", + 'images:multiupload' => "Herramienta MultiCarga de Flash", + 'images:multiupload:todo' => "Selecciona uno a más archivos para cargar..", + 'album' => "Álbum de Fotos", + 'albums' => "Álbumnes de Fotos", + 'album:slideshow' => "Ver presentación de fotos", + 'album:yours' => "Tu álbum de fotos", + 'album:yours:friends' => "Álbum de fotos de tus amigos", + 'album:user' => "Álbum de fotos de %s", + 'album:friends' => "Álbum de fotos de los amigos de %s", + 'album:all' => "Todos los álbumnes de fotos", + 'album:group' => "Grupo de álbumnes", + 'item:object:image' => "Fotos", + 'item:object:album' => "Álbumnes", + 'tidypics:enablephotos' => 'Habilitar Álbumnes de foto del Grupo', + 'tidypics:editprops' => 'Editar Propiedades de Imagen', + 'tidypics:mostcommented' => 'imagenes más comentadas', + 'tidypics:mostcommentedthismonth' => 'Más comentadas este mes', + 'tidypics:mostcommentedtoday' => 'Más comentadas del día de hoy', + 'tidypics:mostviewed' => 'Imagenes más vistas', + 'tidypics:mostvieweddashboard' => 'tablero m&as visto', + 'tidypics:mostviewedthisyear' => 'Más vistas este año', + 'tidypics:mostviewedthismonth' => 'Más vistas este mes', + 'tidypics:mostviewedlastmonth' => 'Más vistas el &ultimo mes', + 'tidypics:mostviewedtoday' => 'Más vistas durante el día de hoy', + 'tidypics:recentlyviewed' => 'Imagenes vistas recientemente', + 'tidypics:mostrecent' => 'Imagenes vistas más recientemente', + 'tidypics:yourmostviewed' => 'Tu imagen más vista', + 'tidypics:yourmostrecent' => 'Tu imagen más reciente', + 'tidypics:friendmostviewed' => "La imagen más vista de %s", + 'tidypics:friendmostrecent' => "La imagen más reciente de %s", + 'tidypics:highestrated' => "Imagenes mejor catalogadas", + 'tidypics:viewsbyowner' => "Vistas: %s por %s (no te incluye a ti)", + 'tidypics:viewsbyothers' => "Vistas: %s (%s por ti)", + 'tidypics:administration' => 'Administración de Tidypics', + 'tidypics:stats' => 'Estatus', + + //settings + 'tidypics:settings' => 'Configuración', + 'tidypics:admin:instructions' => 'Este es el corazón de las preferencias de Tidypics. Cambialas y luego guardalas.', + 'tidypics:settings:image_lib' => "Libreria de Imagenes: ", + 'tidypics:settings:download_link' => "Mostrar vinculo de descarga", + 'tidypics:settings:tagging' => "Habilitar etiquetas en las fotos", + 'tidypics:settings:photo_ratings' => "Habilitar ratings de fotos(requiere instalar el e plugin de Miguel Montes o compatible)", + 'tidypics:settings:exif' => "Mostrar data de EXIF", + 'tidypics:settings:view_count' => "Ver contador", + 'tidypics:settings:grp_perm_override' => "Permitir acceso completo a los miembros de este grupo al album de fotos", + 'tidypics:settings:maxfilesize' => "Tama�o máximo de la imagen en megabytes (MB):", + 'tidypics:settings:quota' => "Usuario/Grupo Cuota (MB) - 0 MB de cuota", + 'tidypics:settings:watermark' => "Introduce el texto que aparecerá en la marca de agua - ImageMagick Cmdline debe ser seleccionado para la libreria de imagenes", + 'tidypics:settings:im_path' => "Ingresa la ruta de tu ImageMagick commands (incluye el slash)", + 'tidypics:settings:img_river_view' => "�Cuántas entradas deseas para cada grupo de imágenes cargadas", + 'tidypics:settings:album_river_view' => "Muestra la portada del álbum o el set de fotos para el álbum nuevo", + 'tidypics:settings:largesize' => "Tamaño inicial de la imagen", + 'tidypics:settings:smallsize' => "Tamaño de imagen de vista del álbum", + 'tidypics:settings:thumbsize' => "Tama�o de imagen miniatura", + + //actions + + 'album:create' => "Crear nuevo álbum", + 'album:add' => "Añadir Álbum de fotos", + 'album:addpix' => "ñadir fotos al Álbum", + 'album:edit' => "Editar álbum", + 'album:delete' => "Borrar álbum", + + 'image:edit' => "Editar imagen", + 'image:delete' => "Borrar imagen", + 'image:download' => "Descargar imagen", + + //forms + + 'album:title' => "Titulo", + 'album:desc' => "Descripción", + 'album:tags' => "Etiquetas", + 'album:cover' => "�Desea hacer de esta imagen la portada del álbum?", + 'tidypics:quota' => "Cuota usada:", + + //views + + 'image:total' => "Imagenes en el álbum:", + 'image:by' => "Imagenes añadidas por", + 'album:by' => "Álbum creador por", + 'album:created:on' => "Creado", + 'image:none' => "Ninguna imagen ha sido añadida aún.", + 'image:back' => "Anterior", + 'image:next' => "Siguiente", + + // tagging + 'tidypics:taginstruct' => 'Seleccciona el área que deseas etiquetar', + 'tidypics:deltag_title' => 'Seleccionas las etiquetas a borrar', + 'tidypics:finish_tagging' => 'Detener etiquetado', + 'tidypics:tagthisphoto' => 'Etiquetar esta foto', + 'tidypics:deletetag' => 'Borrar etiqueta de la foto', + 'tidypics:actiontag' => 'Etiqueta', + 'tidypics:actiondelete' => 'Borrar', + 'tidypics:actioncancel' => 'Cancelar', + 'tidypics:inthisphoto' => 'En esta foto', + 'tidypics:usertag' => "Fotos etiquetadas con %s", + 'tidypics:phototagging:success' => 'La etiqueta de la foto fue añadida exitosamente', + 'tidypics:phototagging:error' => 'Ocurrió un error inesperado durante el etiquetado', + 'tidypics:deletetag:success' => 'Las etiquetas seleccionadas fueron borradas exitosamente', + + + //rss + 'tidypics:posted' => 'publicar una foto:', + + //widgets + + 'tidypics:widget:albums' => "Álbumnes de fotos", + 'tidypics:widget:album_descr' => "Mosrar tu último álbum de fotos", + 'tidypics:widget:num_albums' => "Número de álbumnes a mostrar", + 'tidypics:widget:latest' => "Latest Photos", + 'tidypics:widget:latest_descr' => "Display your latest photos", + 'tidypics:widget:num_latest' => "Number of images to display", + 'album:more' => "Ver todos los álbumnes", + + // river + + //images + 'image:river:created' => "%s añadio la foto %s al álbum %s", + 'image:river:item' => "una foto", + 'image:river:annotate' => "un comentario en la foto", + 'image:river:tagged' => "fue etiquetada en la foto", + + //albums + 'album:river:created' => "%s creo un nuevo álbum de fotos", + 'album:river:group' => "en el grupo", + 'album:river:item' => "un álbum", + 'album:river:annotate' => "un comentario en el álbum de fotos", + + // notifications + 'tidypics:newalbum' => 'Nuevo álbum de fotos', + + + // Status messages + + 'tidypics:upl_success' => "Tu imagen fue cargada exitosamente.", + 'image:saved' => "Tu imagen fue guardada exitosamente.", + 'images:saved' => "Todas tus imagenes fueron guardadas exitosamente.", + 'image:deleted' => "Tu imagen fue borrada exitosamente.", + 'image:delete:confirm' => "�Estás seguro de que deseas borrar esta imagen?", + 'images:edited' => "Tu imagen fue editada exitosamente.", + + 'album:edited' => "Tu álbum fue cargado exitosamente.", + 'album:saved' => "Tu álbum fue guardado exitosamente.", + 'album:deleted' => "Tu álbum fue borrado exitosamente.", + 'album:delete:confirm' => "�Estás seguro de que deseas borrar esta imagen?", + 'album:created' => "Tu nuevo álbum ha sido creado.", + 'tidypics:settings:save:ok' => 'Las preferencias del plugin de Tidypics han sido exitosamente guardadas', + + 'tidypics:upgrade:success' => 'La actualización de Tidypics ha sido un exito', + + //Error messages + + 'tidypics:partialuploadfailure' => "Ocurrieron errores mientas se cargaban algunas de las imagenes (%s de %s imagenes).", + 'tidypics:completeuploadfailure' => "Carga de imagenes fallidas.", + 'tidypics:exceedpostlimit' => "Las imagenes son muy grandes - trate de cargar imagenes m&ás pequeñas.", + 'tidypics:noimages' => "Ninguna imagen fue seleccionada.", + 'tidypics:image_mem' => "La image is muy grande - demasiados bytes", + 'tidypics:image_pixels' => "La image tiene demasiados pixeles", + 'tidypics:unk_error' => "Error de carga desconocido", + 'tidypics:save_error' => "Error desconocido guardando la imagen en el servidor", + 'tidypics:not_image' => "Este no es un tipo de imagen soportada por el sistema", + 'image:deletefailed' => "Tu imagen no pudo ser borrada en este momento.", + 'image:downloadfailed' => "Lo sentimos; esta imagen no está disponible en este momento.", + 'tidypics:nosettings' => "El Administrador de este sitio no ha configurado las preferencias de los álbumnes de fotos.", + 'tidypics:exceed_quota' => "Has excedido la cuota asignada por el administrador", + 'images:notedited' => "No todas las imagenes fueron actualizas exitosamente", + + 'album:none' => "No ha sido creado ningún álbum aún.", + 'album:uploadfailed' => "Lo sentimos; no pudimos guardar tu álbum.", + 'album:deletefailed' => "Tu álbum no pudo ser borrado en este momento.", + 'album:blank' => "Por favor, dale a este Álbum un titulo y una descripción.", + + 'tidypics:upgrade:failed' => "La actualización de Tidypics ha fallado", + ); + + add_translation("es",$spanish); +?> \ No newline at end of file diff --git a/plugins/tidypics/languages/fr.php b/plugins/tidypics/languages/fr.php new file mode 100644 index 0000000000000000000000000000000000000000..ceca628073992be06cf1f2f2c760fce1ed9c47a9 --- /dev/null +++ b/plugins/tidypics/languages/fr.php @@ -0,0 +1,159 @@ +<?php + +// Generated by TranslationBrowser 20091025-06:26:52 PM + +$french = array( + 'untitled' => "Sans titre" , + 'image' => "Image" , + 'images' => "Images" , + 'caption' => "Légende" , + 'photos' => "Photos" , + 'images:upload' => "Charger des images" , + 'images:multiupload' => "Outil Flash de chargement multi fichiers" , + 'images:multiupload:todo' => "Sélectionnez un ou plusieurs fichiers à charger." , + 'album' => "Album photo" , + 'albums' => "Albums photo" , + 'album:slideshow' => "Voir diaporama" , + 'album:yours' => "Vos albums photo" , + 'album:yours:friends' => "Les albums photo de vos amis" , + 'album:user' => "Albums photo de %s" , + 'album:friends' => "Albums photo des amis de %s" , + 'album:all' => "Tout les albums photo" , + 'album:group' => "Albums de groupe" , + 'item:object:image' => "Photos" , + 'item:object:album' => "Albums" , + 'tidypics:uploading:images' => "Veuillez patientez, nous chargeons les fichiers." , + 'tidypics:enablephotos' => "Activer les albums photo pour les groupes" , + 'tidypics:editprops' => "Modifier les propriétés des images" , + 'tidypics:mostcommented' => "Images les plus commentées." , + 'tidypics:mostcommentedthismonth' => "Les plus commentés ce mois-ci" , + 'tidypics:mostcommentedtoday' => "Les plus commentés ce jour-ci" , + 'tidypics:mostviewed' => "Images les plus vues" , + 'tidypics:mostvieweddashboard' => "Tableaux de bord les plus vus" , + 'tidypics:mostviewedthisyear' => "Les plus vus cette année." , + 'tidypics:mostviewedthismonth' => "Les plus vus ce mois-ci" , + 'tidypics:mostviewedlastmonth' => "Les plus vus le mois dernier" , + 'tidypics:mostviewedtoday' => "Les plus vus aujourd'hui" , + 'tidypics:recentlyviewed' => "Images récemment vues" , + 'tidypics:recentlycommented' => "Image récemment commentées" , + 'tidypics:mostrecent' => "Images les plus récentes" , + 'tidypics:yourmostviewed' => "Vos images les plus vues" , + 'tidypics:yourmostrecent' => "Vos images les plus récentes" , + 'tidypics:friendmostviewed' => "Les images les plus vues de %s" , + 'tidypics:friendmostrecent' => "Les images les plus récentes de %s" , + 'tidypics:highestrated' => "Les images les mieux notées" , + 'tidypics:views' => "Vues: %s" , + 'tidypics:viewsbyowner' => "par % membres (vous exclus)" , + 'tidypics:viewsbyothers' => "(%s par vous)" , + 'tidypics:administration' => "Administration Tydipics" , + 'tidypics:stats' => "Stats" , + 'tidypics:settings' => "Paramétrages" , + 'tidypics:admin:instructions' => "Réglages principaux de Tydipics. Modifiez les pour votre usage et cliquez sur Sauvegarder" , + 'tidypics:settings:image_lib' => "Librairie graphique" , + 'tidypics:settings:thumbnail' => "Création des vignettes" , + 'tidypics:settings:download_link' => "Voir le lien de download" , + 'tidypics:settings:tagging' => "Activer les tags sur les photos" , + 'tidypics:settings:photo_ratings' => "Activer les notations des photos (nécessite le rate plugin de Miguel Montes ou compatible)" , + 'tidypics:settings:exif' => "Voir les données EXIF" , + 'tidypics:settings:view_count' => "Voir le compteur" , + 'tidypics:settings:grp_perm_override' => "Autoriser l'acés total aux membres du groupe" , + 'tidypics:settings:maxfilesize' => "Taille maximum des images en Mb:" , + 'tidypics:settings:quota' => "Quota Utilisateur/Groupe (Mb) - O égal pas de quota" , + 'tidypics:settings:watermark' => "Entrez le texte qui doit figure sur le WaterMark - fonction non vraiment sure." , + 'tidypics:settings:im_path' => "Chemin de l'exécutable ImageMagick, terminé par un slash" , + 'tidypics:settings:img_river_view' => "Combien d'entrées dans le river pour chaque lot de traitement des fichiers chargés" , + 'tidypics:settings:album_river_view' => "Montrer la couverture de l'album ou un ensemble de photos pour tout nouvel album" , + 'tidypics:settings:largesize' => "Taille initiale de l'image" , + 'tidypics:settings:smallsize' => "Taille de la vue de l'album" , + 'tidypics:settings:thumbsize' => "Taille des vignettes" , + 'tidypics:settings:im_id' => "Identifiant de l'image" , + 'album:create' => "Créer un nouvel album" , + 'album:add' => "Ajouter un Album photo" , + 'album:addpix' => "Ajouter des photos à l'album" , + 'album:edit' => "Modifier l'album" , + 'album:delete' => "Supprimer l'album" , + 'image:edit' => "Modifier l'image" , + 'image:delete' => "Supprimer l'image" , + 'image:download' => "Télécharger l'image" , + 'album:title' => "Titre" , + 'album:desc' => "Description" , + 'album:tags' => "Tags" , + 'album:cover' => "Faire de cette image la couverture de l'album" , + 'tidypics:quota' => "Quota utilisé:" , + 'image:total' => "Images dans l'album:" , + 'image:by' => "Image ajoutée par" , + 'album:by' => "Album créé par" , + 'album:created:on' => "Création" , + 'image:none' => "Aucune image n'a encore été ajoutée" , + 'image:back' => "Précédent" , + 'image:next' => "Suivant" , + 'tidypics:taginstruct' => "Sélectionnez la zone que vous souhaitez tagger" , + 'tidypics:deltag_title' => "Sélectionnez le tag à supprimer" , + 'tidypics:finish_tagging' => "Arrêter de tagger" , + 'tidypics:tagthisphoto' => "Tagger cette photo" , + 'tidypics:deletetag' => "Supprimer le tag d'une photo" , + 'tidypics:actiontag' => "Tag" , + 'tidypics:actiondelete' => "Supprimer" , + 'tidypics:actioncancel' => "Annuler" , + 'tidypics:inthisphoto' => "Dans cette photo" , + 'tidypics:usertag' => "Photo taggée par %s" , + 'tidypics:phototagging:success' => "La photo a été correctement taggée." , + 'tidypics:phototagging:error' => "Erreur innatendue durant le taggage" , + 'tidypics:deletetag:success' => "Les tags sélectionnés ont correctement été supprimés" , + 'tidypics:tag:subject' => "Vous avez été taggé dans une photo !!!" , + 'tidypics:tag:body' => "Vous avez été taggé dans la photo %s par %s !!! +La photo peut être consultée ici: %s" , + 'tidypics:posted' => "a posté une photo" , + 'tidypics:widget:albums' => "Albums photo" , + 'tidypics:widget:album_descr' => "Échantillon de vos albums photo" , + 'tidypics:widget:num_albums' => "Nombre de photos à montrer" , + 'tidypics:widget:latest' => "Dernières photos" , + 'tidypics:widget:latest_descr' => "Montrer les dernières photos" , + 'tidypics:widget:num_latest' => "Nombre d'images à montrer" , + 'album:more' => "Voir tout les albums" , + 'image:river:created' => "%s a ajouté la photo %s à l'album %s" , + 'image:river:item' => "une photo" , + 'image:river:annotate' => "commentaire sur la photo" , + 'image:river:tagged' => "a été taggé sur la photo" , + 'album:river:created' => "%s a créé un nouvel album photo" , + 'album:river:group' => "dans le groupe" , + 'album:river:item' => "un album" , + 'album:river:annotate' => "un commentaire sur l'album photo" , + 'tidypics:newalbum' => "Nouvel album photo" , + 'tidypics:upl_success' => "Vos images ont été correctement chargées." , + 'image:saved' => "Votre image a été correctement enregistrée" , + 'images:saved' => "Toutes les images ont été correctement enregistrées" , + 'image:deleted' => "Votre image a correctement été supprimée" , + 'image:delete:confirm' => "Confirmez-vous la suppression de cette image" , + 'images:edited' => "Vos images ont été correctement mises à jour" , + 'album:edited' => "Votre album a correctement été mis à jour" , + 'album:saved' => "Votre album a correctement été enregistré" , + 'album:deleted' => "Votre album a correctement été supprimé" , + 'album:delete:confirm' => "Confirmez-vous la suppression de cet album" , + 'album:created' => "Votre nouvel album a été créé" , + 'tidypics:settings:save:ok' => "Réglages du plugin Tydipics enregistrés" , + 'tidypics:upgrade:success' => "Mise à jour de Tydipics effectuée" , + 'tidypics:partialuploadfailure' => "Des erreurs sont survenues durant le chargement des images (%s sur %s images)" , + 'tidypics:completeuploadfailure' => "Echec du chargement des images " , + 'tidypics:exceedpostlimit' => "Trop d'images trop lourdes - essayez de charges des images plus petites" , + 'tidypics:noimages' => "Aucune image sélectionnée" , + 'tidypics:image_mem' => "Image trop large - taille trop grosse" , + 'tidypics:image_pixels' => "L'image a trop de pixels" , + 'tidypics:unk_error' => "Erreur inconnue de chargement" , + 'tidypics:save_error' => "Erreur inconnue lors de l'enregistrement de l'image sur le serveur" , + 'tidypics:not_image' => "Type d'image non reconnu" , + 'image:deletefailed' => "Votre image n'a pu être supprimée" , + 'image:downloadfailed' => "Désolé, image indisponible pour le moment" , + 'tidypics:nosettings' => "L'administrateur n'a pas effectué les reglages minimaux des albums" , + 'tidypics:exceed_quota' => "Quota fixé par l'administrateur dépassé" , + 'images:notedited' => "Toutes les images n'ont pas été correctement mises à jour" , + 'album:none' => "Aucun album encore créé" , + 'album:uploadfailed' => "Désolé, nous ne pouvons pas enregistrer l'album" , + 'album:deletefailed' => "Votre album ne peut pas être supprimé pour le moment" , + 'album:blank' => "Donnez un titre et une description à cet album" , + 'tidypics:upgrade:failed' => "Mise à jour de Tydipics infructueuse" +); + +add_translation('fr', $french); + +?> \ No newline at end of file diff --git a/plugins/tidypics/languages/he.php b/plugins/tidypics/languages/he.php new file mode 100644 index 0000000000000000000000000000000000000000..8edee9c0cc08455d82ed7f33cec1f1ae89f22f90 --- /dev/null +++ b/plugins/tidypics/languages/he.php @@ -0,0 +1,149 @@ +<?php + +// Generate By translationbrowser. + +$hebrew = array( + 'image' => "תמונה" , + 'images' => "תמונות" , + 'caption' => "כיתוב" , + 'photos' => "תמונות" , + 'images:upload' => "העלאת תמונות" , + 'images:multiupload' => "כלי פלאש להעלאת תמונות רבות" , + 'images:multiupload:todo' => "בחרו קובץ אחד או יותר" , + 'album' => "אלבום תמונות" , + 'albums' => "אלבומי תמונות" , + 'album:slideshow' => "צפיה כמצגת" , + 'album:yours' => "אלבומי התמונות שלך" , + 'album:yours:friends' => "אלבומי תמונות של חברים" , + 'album:user' => "אלבומי תמונות של %s" , + 'album:friends' => "אלבומי התמונות של החברים של %s " , + 'album:all' => "כל אלבומי התמונות באתר" , + 'album:group' => "אלבומים קבוצתיים" , + 'item:object:image' => "תמונות" , + 'item:object:album' => "אלבומים" , + 'tidypics:enablephotos' => "אפשר אלבומי תמונות קבוצתיים" , + 'tidypics:editprops' => "ערוך מאפייני תמונה" , + 'tidypics:mostcommented' => "תמונות עם הכי הרבה תגובות" , + 'tidypics:mostcommentedthismonth' => "הכי הרבה תגובות בחודש זה" , + 'tidypics:mostcommentedtoday' => "הכי הרבה תגובות היום" , + 'tidypics:mostviewed' => "תמונות אשר נצפו הכי הרבה" , + 'tidypics:mostvieweddashboard' => "הדף אשר נצפה הכי הרבה" , + 'tidypics:mostviewedthisyear' => "נצפה הכי הרבה השנה" , + 'tidypics:mostviewedthismonth' => "נצפה הכי הרבה החודש" , + 'tidypics:mostviewedlastmonth' => "נצפה הכי הרבה בחודש שעבר" , + 'tidypics:mostviewedtoday' => "נצפה הכי הרבה היום" , + 'tidypics:recentlyviewed' => "תמונות אשר נצפו לאחרונה" , + 'tidypics:mostrecent' => "תמונות חדשות" , + 'tidypics:yourmostviewed' => "תמונות שלך אשר נצפו הכי הרבה" , + 'tidypics:yourmostrecent' => "התמונות הכי חדשות שלך" , + 'tidypics:friendmostviewed' => "תמונות של %s אשר נצפו הכי הרבה" , + 'tidypics:friendmostrecent' => "תמונות החדשות ביותר של %s" , + 'tidypics:highestrated' => "תמונות בעלי הדירוג הגבוה ביותר" , + 'tidypics:viewsbyowner' => "צפיות: %s על ידי %s משתמשים (לא כולל אותך)" , + 'tidypics:viewsbyothers' => "צפיות: %s (%s על ידיך)" , + 'tidypics:administration' => "ניהול Tidypics" , + 'tidypics:stats' => "סטטיסטיקה" , + 'tidypics:settings' => "הגדרות" , + 'tidypics:admin:instructions' => "אלה הגדרות הליבה של Tidypics. שנה אותן לפי הצורך ולחץ על שמור" , + 'tidypics:settings:image_lib' => "ספריית תמונות:" , + 'tidypics:settings:download_link' => "הצג לינק להורדה" , + 'tidypics:settings:tagging' => "אפשר תיוג תמונות" , + 'tidypics:settings:photo_ratings' => "אפשר דירוג תמונות, דורש תוסף דירוג של Miguel Montes או דומה" , + 'tidypics:settings:exif' => "הצג נתוני EXIF" , + 'tidypics:settings:view_count' => "מונה צפיה" , + 'tidypics:settings:grp_perm_override' => "אפשר לחברי קבוצה גישה מלאה לאלבומים קבוצתיים" , + 'tidypics:settings:maxfilesize' => "גודל תמונה מירבי בMB" , + 'tidypics:settings:quota' => "מכסה בMB למשתמש/קבוצה - 0 שווה ללא מכסה" , + 'tidypics:settings:watermark' => "הזן טקסט אשר יופיע בסימן המים - יש לבחור ב ImageMagick Cmdline עבור ספריית התמונות" , + 'tidypics:settings:im_path' => "הזן את הנטיב לפקודות ImageMagick ללא לוכסן בסוף" , + 'tidypics:settings:img_river_view' => "כמה רשומות במה חדש עבור כל מקבץ תמונות אשר נוסף" , + 'tidypics:settings:album_river_view' => "הצג תמונה אחת או מקבץ תמונות עבור אלבום חדש" , + 'tidypics:settings:largesize' => "גודל תמונה בסיסי" , + 'tidypics:settings:smallsize' => "גודל תמונה בתצוגת אלבום" , + 'tidypics:settings:thumbsize' => "גודל תמונה ממוזערת" , + 'album:create' => "יצירת אלבום חדש" , + 'album:add' => "הוספת אלבום" , + 'album:addpix' => "הוספת תמונות לאלבום" , + 'album:edit' => "עריכת אלבום" , + 'album:delete' => "מחיקת אלבום" , + 'image:edit' => "עריכת תמונה" , + 'image:delete' => "מחיקת תמונה" , + 'image:download' => "הורדת תמונה" , + 'album:title' => "כותרת" , + 'album:desc' => "תאור" , + 'album:tags' => "תגים" , + 'album:cover' => "קבע תמונה זו כעטיפה " , + 'tidypics:quota' => "שימוש מכסה" , + 'image:total' => "תמונות באלבום:" , + 'image:by' => "תמונה נוספה על ידי" , + 'album:by' => "אלבום נוצר על ידי" , + 'album:created:on' => "יצר/ה" , + 'image:none' => "טרם נוספו תמונות" , + 'image:back' => "הקודם" , + 'image:next' => "הבא" , + 'tidypics:taginstruct' => "בחר אזור להוספת תג" , + 'tidypics:deltag_title' => "בחר תגים למחיקה" , + 'tidypics:finish_tagging' => "הפסק לתייג" , + 'tidypics:tagthisphoto' => "תייג תמונה זו" , + 'tidypics:deletetag' => "מחק תג תמונה" , + 'tidypics:actiontag' => "תג" , + 'tidypics:actiondelete' => "מחיקה" , + 'tidypics:actioncancel' => "ביטול" , + 'tidypics:inthisphoto' => "בתמונה זו" , + 'tidypics:usertag' => "תמונות המתוייגות במשתמש %s" , + 'tidypics:phototagging:success' => "התג נוסף בהצלחה" , + 'tidypics:phototagging:error' => "אירע שגיאה בתהליך התיוג" , + 'tidypics:deletetag:success' => "התגים נמחקו בהצלחה" , + 'tidypics:posted' => "הוסיף/ה תמונה" , + 'tidypics:widget:albums' => "אלבומי תמונות" , + 'tidypics:widget:album_descr' => "הצג את האלבומים החדשים שלך" , + 'tidypics:widget:num_albums' => "מספר האלבומים לתצוגה" , + 'tidypics:widget:latest' => "Latest Photos", + 'tidypics:widget:latest_descr' => "Display your latest photos", + 'tidypics:widget:num_latest' => "Number of images to display", + 'album:more' => "צפיה בכל האלבומים" , + 'image:river:created' => "%s הוסיף/ה את התמונה %s לאלבום %s" , + 'image:river:item' => "תמונה" , + 'image:river:annotate' => "תגובה לתמונה" , + 'album:river:created' => "%s יצר/ה אלבום תמונות חדש" , + 'album:river:group' => "בקבוצה" , + 'album:river:item' => "אלבום" , + 'album:river:annotate' => "תגובה באלבום התמונות" , + 'tidypics:newalbum' => "אלבום תמונות חדש" , + 'tidypics:upl_success' => "התמונות הועלו בהצלחה" , + 'image:saved' => "התמונה נשמרה בהצלחה" , + 'images:saved' => "כל התמונות נשמרו בהצלחה" , + 'image:deleted' => "התמונה נמחקה בהצלחה" , + 'image:delete:confirm' => "בטוח? למחוק תמונה זו?" , + 'images:edited' => "התמונות עודכנו בהצלחה" , + 'album:edited' => "האלבום עודכן בהצלחה" , + 'album:saved' => "האלבום נשמר בהצלחה" , + 'album:deleted' => "האלבום נמחק בהצלחה" , + 'album:delete:confirm' => "בטוח? למחוק אלבום זה?" , + 'album:created' => "האלבום החדש נוצר" , + 'tidypics:settings:save:ok' => "הגדרות התוסף Tidypics נשמרו בהצלחה" , + 'tidypics:upgrade:success' => "Tidypics שודרג בהצלחה" , + 'tidypics:partialuploadfailure' => "אירעו שגיאות בהעלאת חלק מהתמונות (%s מתוך %s תמונות)." , + 'tidypics:completeuploadfailure' => "העלאת התמונות נכשל" , + 'tidypics:exceedpostlimit' => "יותר מדי תמונות גדולות - נסה פחות תמונות או תמונות קטנות יותר" , + 'tidypics:noimages' => "לא נבחרו תמונות" , + 'tidypics:image_mem' => "התמונה גדולה מדי - יותר מדי ביטים" , + 'tidypics:image_pixels' => "לתמונה יותר מדי פיקסלים" , + 'tidypics:unk_error' => "שגיאה לא מוכרת בהעלאת תמונות" , + 'tidypics:save_error' => "שגיאה לא מוכרת בשמירת תמונות" , + 'tidypics:not_image' => "סוק הקובץ לא מזוהה" , + 'image:deletefailed' => "לא ניתן היה למחוק תמונה זו " , + 'image:downloadfailed' => "מצטערים התמונה אינה זמינה כרגע" , + 'tidypics:nosettings' => "מנהל הרשת טרם קבע הגדרות עבור אלבומי תמונות" , + 'tidypics:exceed_quota' => "עברת את מגבלת המכסה הנקבע על ידי מנהל הרשת" , + 'images:notedited' => "לא עודכנו כל התמונות בהצלחה" , + 'album:none' => "טרם נוצרו אלבומים" , + 'album:uploadfailed' => "מצטערים לא הצלחנו לשמור את האלבום שלך" , + 'album:deletefailed' => "לא ניתן היה למחוק את האלבום" , + 'album:blank' => "אנא קבע שם ותאור עבור אלבום זה" , + 'tidypics:upgrade:failed' => "שדרוג Tidypics נכשל" +); + +add_translation('he', $hebrew); + +?> \ No newline at end of file diff --git a/plugins/tidypics/languages/it.php b/plugins/tidypics/languages/it.php new file mode 100644 index 0000000000000000000000000000000000000000..36863851c379baffeba9822b85ed3f6df3e1f4e2 --- /dev/null +++ b/plugins/tidypics/languages/it.php @@ -0,0 +1,113 @@ +<?php + + $italian = array( + + // Menu items and titles + + 'image' => "Immagine", + 'images' => "Immagini", + 'caption' => "Caption", + 'photos' => "Foto", + 'images:upload' => "Carica Immagine", + 'album' => "Album fotografico", + 'albums' => "Album fotografici", + 'album:yours' => "Il tuo Album fotografico", + 'album:yours:friends' => "Album Foto degli amici", + 'album:user' => "Album foto di %s", + 'album:friends' => "Album foto degli amici di %s", + 'album:all' => "Tutti gli album di foto", + 'album:group' => "Gruppi di album", + 'item:object:image' => "Foto", + 'item:object:album' => "Album", + 'tidypics:settings:maxfilesize' => "Dimensione massima dei file in kilo bytes (KB):", + 'tidypics:enablephotos' => 'Attiva Group Photo Albums', + 'tidypics:editprops' => 'Modifica le propriet� della immagine', + + //actions + + 'album:create' => "Crea un nuovo album", + 'album:add' => "Aggiungi un foto Album", + 'album:addpix' => "Aggiungi foto all'album", + 'album:edit' => "Modifica album", + 'album:delete' => "Cancella album", + + 'image:edit' => "Modifica immagine", + 'image:delete' => "Cancella immagine", + 'image:download' => "Download immagine", + + //forms + + 'album:title' => "Titolo", + 'album:desc' => "Descrizione", + 'album:tags' => "Tags", + 'album:cover' => "Copertina dell'album?", + 'album:cover:yes' => "Si", + 'image:access:note' => "(view access is inherited from the album)", + + //views + + 'image:total' => "immagini nell'album:", + 'image:by' => "immagini aggiunte da", + 'album:by' => "Album creato da", + 'album:created:on' => "Creato", + 'image:none' => "Non sono ancora state aggiunte immagini.", + 'image:back' => "Indietro", + 'image:next' => "Avanti", + + //widgets + + 'album:widget' => "Album Fotografici", + 'album:more' => "Vedi tutti gli albums", + 'album:widget:description' => "Visualizza il tuo ultimo album fotografico", + 'album:display:number' => "Numero di album da mostrare", + 'album:num_albums' => "Numero di album da mostrare", + + // river + + //images + 'image:river:created' => "%s uploaded", + 'image:river:item' => "una immagine", + 'image:river:annotate' => "a comment on the image", + + //albums + 'album:river:created' => "%s created a new photo album: ", + 'album:river:item' => "an album", + 'album:river:annotate' => "un commento nel foto album", + + // notifications + 'tidypics:newalbum' => 'Nuovo album di foto', + + + // Status messages + + 'image:saved' => "Immagine salvata.", + 'images:saved' => "Tutte le immagini sono state salvate.", + 'image:deleted' => "Immagine cancellata.", + 'image:delete:confirm' => "Sei sicuro di volerla cancellare?", + + 'images:edited' => "Immagini modificate.", + 'album:edited' => "Album fotografico aggiornato.", + 'album:saved' => "Album fotografico salvato.", + 'album:deleted' => "L'album � stato cancellato.", + 'album:delete:confirm' => "Sei sicuro di voler cancellare questo album?", + 'album:created' => "Nuovo Album creato.", + 'tidypics:status:processing' => "Attendere ....", + + //Error messages + + 'image:none' => "Non ci sono immagini.", + 'image:uploadfailed' => "il file non � stato caricato:", + 'image:deletefailed' => "L'immagine non puo essere cancellata in questo momento.", + 'image:downloadfailed' => "Spiacente; questa immagine non � attualmente disponibile.", + + 'image:notimage' => "Sono accettate immagini jpg, gif o png delle dimensioni entro i limiti.", + 'images:notedited' => "Non tutte le immagini sono state caricate", + + 'album:none' => "Nessun album � stato ancora creato.", + 'album:uploadfailed' => "Spiacente; non � possibile salvare l'album.", + 'album:deletefailed' => "L'album non pu� essere cancellato.", + 'album:blank' => "Dai a quest'album un titolo e una descrizione." + ); + + add_translation("it",$italian); +?> \ No newline at end of file diff --git a/plugins/tidypics/languages/pl.php b/plugins/tidypics/languages/pl.php new file mode 100644 index 0000000000000000000000000000000000000000..7f48b488bb9e96ca2cc4b05b7f614ae6080de983 --- /dev/null +++ b/plugins/tidypics/languages/pl.php @@ -0,0 +1,113 @@ +<?php + /** + * Elgg tidypics plugin language pack + * + */ + + $polish = array( + + // Menu items and titles + + 'image' => "Obrazek", + 'images' => "Obrazki", + 'caption' => "Opis", + 'photos' => "Zdjęcia", + 'images:upload' => "Dodaj obrazki", + 'album' => "Album zdjęciowy", + 'albums' => "Albumy zdjęciowe", + 'album:yours' => "Twoje albumy", + 'album:yours:friends' => "Albumy twoich znajomych", + 'album:user' => "Albumy użytkownika %s", + 'album:friends' => "Albumy przyjaciół użytkownika %s", + 'album:all' => "Wszystkie publiczne albumy", + 'album:group' => "Albumy rejsu", + 'item:object:image' => "Zdjęcia", + 'item:object:album' => "Albumy", + 'tidypics:settings:maxfilesize' => "Maximum file size in kilo bytes (KB):", + + 'tidypics:editprops' => 'Edycja obrazu Właściwości', + + //actions + + 'album:create' => "Nowy album", + 'album:add' => "Dodaj album zdjęciowy", + 'album:addpix' => "Dodaj zdjęcia", + 'album:edit' => "Edytuj album", + 'album:delete' => "Skasuj album", + + 'image:edit' => "Edytuj obrazek", + 'image:delete' => "Skasuj obrazek", + 'image:download' => "Pobierz obrazek", + + //forms + + 'album:title' => "Tytuł albumu", + 'album:desc' => "Opis (widoczny tylko dla twórcy)", + 'album:tags' => "Tagi", + 'album:cover' => "Ustaw jako okładkę albumu?", + 'album:cover:yes' => "Tak", + 'image:access:note' => "(prawa dostępu pobierane są z ustawień albumu)", + + //views + + 'image:total' => "Obrazki w albumie:", + 'image:by' => "Obrazek dodany przez", + 'album:by' => "Album stworzony przez", + 'album:created:on' => "Stworzono", + 'image:none' => "Nie dodano jeszcze żadnych obrazków.", + 'image:back' => "Poprzednia", + 'image:next' => "Kolejna", + + //widgets + + 'album:widget' => "Albumy zdjęciowe", + 'album:more' => "Pokaż wszystkie albumy", + 'album:widget:description' => "Pokazuje twoje ostatnie albumy zdjęciowe", + 'album:display:number' => "Liczba wyświetlanych albumów", + 'album:num_albums' => "Liczba wyświetlanych albumów", + + // river + + //images + 'image:river:created' => "wgrano %s", + 'image:river:item' => "obrazek", + 'image:river:annotate' => "%s skomentował", + + //albums + 'album:river:created' => "Stworzono %s", + 'album:river:item' => "album", + 'album:river:annotate' => "%s skomentował", + + // Status messages + + 'image:saved' => "Twój obrazek został pomyślnie zapisany.", + 'images:saved' => "Wszystkie obrazki zostały pomyślnie zapisane.", + 'image:deleted' => "Twój obrazek został pomyślnie skasowany.", + 'image:delete:confirm' => "Czy jesteś pewien że chcesz skasować ten obrazek?", + + 'images:edited' => "Twoje obrazki zostały pomyślnie zapisane.", + 'album:edited' => "Twój album został pomyślnie zapisany.", + 'album:saved' => "Twój album został pomyślnie zapisany.", + 'album:deleted' => "Twój album został skasowany.", + 'album:delete:confirm' => "Na pewno chcesz skasować ten album?", + 'album:created' => "Stworzono nowy album.", + 'tidypics:status:processing' => "Please wait while we process your picture....", + + //Error messages + + 'image:none' => "Jeszcze nie dodano żadnych obrazków.", + 'image:uploadfailed' => "Pliki nie zapisane:", + 'image:deletefailed' => "Nie udało się skasować obrazka.", + 'image:downloadfailed' => "Nie udało się ściągnąć albumu.", + + 'image:notimage' => "Akceptowane formaty to tylko: jpeg, gif i png, and the allowed file size.", + 'images:notedited' => "Nie wszystkie obrazki zostały zapisane", + + 'album:none' => "Jeszcze nie dodano żadnych albumów.", + 'album:uploadfailed' => "Nie udało się zapisać twojego albumu.", + 'album:deletefailed' => "Nie udało się usunąć twojego albumu.", + 'album:blank' => "Please give this albumu a tytuł and opis." + ); + + add_translation("pl",$polish); +?> \ No newline at end of file diff --git a/plugins/tidypics/languages/ru.php b/plugins/tidypics/languages/ru.php new file mode 100644 index 0000000000000000000000000000000000000000..2722450c3c9dc389312846b1acbc3433cb3cfbe2 --- /dev/null +++ b/plugins/tidypics/languages/ru.php @@ -0,0 +1,113 @@ +<?php + + $russian = array( + + // Menu items and titles + + 'image' => "Фотография", + 'images' => "Фотографии", + 'caption' => "Описание", + 'photos' => "Фотки", + 'images:upload' => "Загрузить Фотки", + 'album' => "Фотоальбом", + 'albums' => "Фотоальбомы", + 'album:yours' => "Ваш Альбом", + 'album:yours:friends' => "Альбомы Ваших Друзей", + 'album:user' => "%s - Фотоальбом", + 'album:friends' => "Альбомы друзей пользователя %s", + 'album:all' => "Все Альбомы Сайта", + 'album:group' => "Альбомы Группы", + 'item:object:image' => "Фотки", + 'item:object:album' => "Альбомы", + 'tidypics:settings:maxfilesize' => "Максимальный размер файла (KB):", + 'tidypics:enablephotos' => 'Включить Альбомы Группы', + 'tidypics:editprops' => 'Редактировать данные фотогографии', + + //actions + + 'album:create' => "Создать новый Альбом", + 'album:add' => "Добавить Альбом", + 'album:addpix' => "Добавить Фотки в Альбом", + 'album:edit' => "Редактировать Альбом", + 'album:delete' => "Стереть Альбом", + + 'image:edit' => "Редактировать Фотку", + 'image:delete' => "Стереть Фотку", + 'image:download' => "Скачать Фотку", + + //forms + + 'album:title' => "Заголовок", + 'album:desc' => "Описание", + 'album:tags' => "Тэги", + 'album:cover' => "Сдеалем Обложку Альбома?", + 'album:cover:yes' => "Да", + 'image:access:note' => "(ыровень доступа как и у основного Альбома)", + + //views + + 'image:total' => "Всего Фоток:", + 'image:by' => "Фотка добавлена:", + 'album:by' => "Альбом принадлежит:", + 'album:created:on' => "Создан:", + 'image:none' => "Пока Фоток не добавлено", + 'image:back' => "Назад", + 'image:next' => "Вперед", + + //widgets + + 'album:widget' => "Фотоальбомы", + 'album:more' => "Посмотреть все Альбомы", + 'album:widget:description' => "Продемонстрировать свой новый Альбом", + 'album:display:number' => "Число Альбомов для показа", + 'album:num_albums' => "Число Альбомов для показа", + + // river + + //images + 'image:river:created' => "%s загрузил", + 'image:river:item' => "фотку", + 'image:river:annotate' => "комментариы к Фотке", + + //albums + 'album:river:created' => "%s создал новый Альбом: ", + 'album:river:item' => "Альбом", + 'album:river:annotate' => "Комментарий к Альбому", + + // notifications + 'tidypics:newalbum' => 'Новый Фото Альбом', + + + // Status messages + + 'image:saved' => "Ваша фотография загружена успешно.", + 'images:saved' => "Все Фотки успешно сохранены.", + 'image:deleted' => "Ваша Фотография стерта.", + 'image:delete:confirm' => "Вы уверены, что хотите стереть эту Фотку?", + + 'images:edited' => "Ваши Фотки успешно обновленны.", + 'album:edited' => "Ваш Альбом обновлен.", + 'album:saved' => "Ваш Альбом сохранен.", + 'album:deleted' => "Ваш Альбом стерт.", + 'album:delete:confirm' => "Вы уверены, что хотите стереть этот Альбом?", + 'album:created' => "Ваш новый Альбом готов.", + 'tidypics:status:processing' => "Подозчдите пока мы загружаем фотку....", + + //Error messages + + 'image:none' => "На данный момент никаких фоток не обнаружено.", + 'image:uploadfailed' => "Файлы не загружены:", + 'image:deletefailed' => "В данный момент эту Фотку стереть невозможно.", + 'image:downloadfailed' => "На данный момент эту фотку просмотреть невозможно.", + + 'image:notimage' => "Допускаются только фотки формата jpeg, gif, или png разрешенного размера.", + 'images:notedited' => "Не все фотографии были обновленны", + + 'album:none' => "Пока никаких Альбомов не имеется.", + 'album:uploadfailed' => "Ваш Альбом сохранить не удалось.", + 'album:deletefailed' => "В данный момент ваш Альбом стереть невозможно.", + 'album:blank' => "Пожалуйста создайте заголовок и описание вашего Альбома.", + ); + + add_translation("ru",$russian); +?> \ No newline at end of file diff --git a/plugins/tidypics/languages/tr.php b/plugins/tidypics/languages/tr.php new file mode 100644 index 0000000000000000000000000000000000000000..fff696c477f6fd6822bce363b9ef5b5b7a52e262 --- /dev/null +++ b/plugins/tidypics/languages/tr.php @@ -0,0 +1,88 @@ +<?php + + /** + * Elgg tidypics plugin language pack + * + * Türkçe Çeviri Orhan Can Ceylan | elggturkiye.com + */ + + +$turkish = array( + 'image' => "Resim" , + 'image:access:note' => "Görüntüleme izni albümden tevarüs edildi." , + 'images' => "Resimler" , + 'caption' => "Açıklama" , + 'photos' => "Resimler" , + 'images:upload' => "Resimleri Yükle" , + 'album' => "Fotoğraf Albümü" , + 'albums' => "Fotoğraf Albümleri" , + 'album:yours' => "Senin Fotoğraf Albümlerin" , + 'album:yours:friends' => "Arkadaşlarının Fotoğraf Albümleri" , + 'album:user' => "%s adlı üyenin fotoğraf albümleri" , + 'album:friends' => "%s adlı üyenin arkadaşlarının fotoğraf albümleri" , + 'album:all' => "Tüm sitenin fotoğraf albümleri" , + 'album:group' => "Grubun Albümleri" , + 'item:object:image' => "Fotoğraflar" , + 'item:object:album' => "Albümler" , + 'tidypics:settings:maxfilesize' => "Bir fotoğrafın maksimum büyüklüğü (kilobyte):" , + 'tidypics:enablephotos' => 'Grup Albümlerini Aktif Et', + 'tidypics:editprops' => 'Fotoğrafın özelliklerini Düzenle', + 'tidypics:newalbum' => 'Yeni Fotoğraf Albümü', + 'album:create' => "Yeni Albüm" , + 'album:add' => "Yeni Fotoğraf Albümü Ekle" , + 'album:addpix' => "Fotoğraf ekle" , + 'album:edit' => "Albümü Düzenle" , + 'album:delete' => "Albümü Sil" , + 'image:edit' => "Resmi Düzenle" , + 'image:delete' => "Resmi Sil" , + 'image:download' => "Resmi İndir" , + 'album:title' => "Başlık" , + 'album:desc' => "Tanım" , + 'album:tags' => "Tagler" , + 'album:cover' => "Bu resim albüm fotoğrafı olsun mu ?" , + 'album:cover:yes' => "Evet" , + 'image:total' => "Albümdeki fotoğraflar" , + 'image:by' => "Fotoğrafı ekleyen " , + 'album:by' => "Albümü oluşturan" , + 'album:created:on' => "Oluşturuldu" , + 'image:none' => "Şuan görünülenecek fotoğraf bulunamadı" , + 'image:back' => "Geri" , + 'image:next' => "İleri" , + 'album:widget' => "Fotoğraf Albümleri" , + 'album:more' => "Tüm albümleri gör" , + 'album:widget:description' => "Son albümleri göster" , + 'album:display:number' => "Gösterilecek albüm sayısı" , + 'album:num_albums' => "Gösterilecek albüm sayısı" , + 'image:river:created' => "%s upload edildi" , + 'image:river:item' => "resim" , + 'image:river:annotate' => "%s yorum yapıldı" , + 'album:river:created' => "%s oluşturuldu" , + 'album:river:item' => "albüm" , + 'album:river:annotate' => "%s yorum yapıldı" , + 'image:saved' => "Fotoğrafınız başarıyla kaydedildi." , + 'images:saved' => "Tüm fotoğraflarınız başarıyla kaydedildi." , + 'image:deleted' => "Fotoğrafınız başarıyla silindi." , + 'image:delete:confirm' => "Bu fotoğrafı silmek istediğinizden emin misiniz ?" , + 'images:edited' => "Fotoğraflarınız başarıyla yüklendi" , + 'album:edited' => "Albümünüz başarıyla güncellendi." , + 'album:saved' => "Albümünüz başarıyla kaydedildi." , + 'album:deleted' => "Albümünüz başarıyla silindi." , + 'album:delete:confirm' => "Albümü silmek istediğinizden emin misiniz ?" , + 'album:created' => "Yeni albümünüz oluşturuldu." , + 'image:uploadfailed' => "Fotoğraflar yüklenemedi :" , + 'image:deletefailed' => "Fotoğrafınız şuan silinemiyor." , + 'image:downloadfailed' => "Üzgünüz, bu fotoğraf şuan uygun değil." , + 'image:notimage' => "Sadece jpeg, gif veya png uzantılı fotoğraflar kabul edilir." , + 'images:notedited' => "Tüm fotoğraflar başarıyla güncellenemedi." , + 'album:none' => "Şuan herhangi bir albüm bulunamadı." , + 'album:uploadfailed' => "Üzgünüm, albümünüz kaydolmadı." , + 'album:deletefailed' => "Albümünüz silinemedi." , + 'tidypics:status:processing' => "Fotoğrafınız işlenirken lütfen bekleyiniz." , + 'album:blank' => "Lütfen albümünüze başlık ve tanım giriniz." + + +); + +add_translation('tr', $turkish); + +?> \ No newline at end of file diff --git a/plugins/tidypics/lib/album.php b/plugins/tidypics/lib/album.php new file mode 100644 index 0000000000000000000000000000000000000000..7cd27dcde28c2c78185622e98f63087b5b910e93 --- /dev/null +++ b/plugins/tidypics/lib/album.php @@ -0,0 +1,19 @@ +<?php +/** + * Tidypics Album class + * + * @package TidypicsAlbum + */ + + +class TidypicsAlbum extends ElggObject { + protected function initialise_attributes() { + parent::initialise_attributes(); + + $this->attributes['subtype'] = "album"; + } + + public function __construct($guid = null) { + parent::__construct($guid); + } +} diff --git a/plugins/tidypics/lib/exif.php b/plugins/tidypics/lib/exif.php new file mode 100644 index 0000000000000000000000000000000000000000..55612a433da18aecca1dcdfdc369f0906cb45173 --- /dev/null +++ b/plugins/tidypics/lib/exif.php @@ -0,0 +1,109 @@ +<?php +/** + * Exif Processing Library + * + * @package TidypicsExif + */ + +/** + * Pull EXIF data from image file + * + * @param TidypicsImage $file + */ +function td_get_exif($file) { + + // catch for those who don't have exif module loaded + if (!is_callable('exif_read_data')) { + return; + } + + $mime = $file->mimetype; + if ($mime != 'image/jpeg' && $mime != 'image/pjpeg') { + return; + } + + $filename = $file->getFilenameOnFilestore(); + $exif = exif_read_data($filename); + create_metadata($file->getGUID(), "tp_exif", serialize($exif), "text", $file->getObjectOwnerGUID(), ACCESS_PUBLIC); +} + +/** + * Grab array of EXIF data for display + * + * @param int $file_guid GUID of TidypicsImage + * @return array|false + */ +function tp_exif_formatted($file_guid) { + + $metadata_exif = get_metadata_byname($file_guid, "tp_exif"); + if (!$metadata_exif) { + // //try to load it from the file if its not in the database + $file = new ElggFile($file_guid); + td_get_exif($file); + unset($file); + $metadata_exif = get_metadata_byname($file_guid, "tp_exif"); + } + + if (!$metadata_exif) { + return false; + } + + $exif = unserialize($metadata_exif["value"]); + + $model = $exif['Model']; + if (!$model) { + $model = "N/A"; + } + $exif_data['Model'] = $model; + + $exposure = $exif['ExposureTime']; + if (!$exposure) { + $exposure = "N/A"; + } + $exif_data['Shutter'] = $exposure; + + //got the code snippet below from http://www.zenphoto.org/support/topic.php?id=17 + //convert the raw values to understandible values + $Fnumber = explode("/", $exif['FNumber']); + if ($Fnumber[1] != 0) { + $Fnumber = $Fnumber[0] / $Fnumber[1]; + } else { + $Fnumber = 0; + } + if (!$Fnumber) { + $Fnumber = "N/A"; + } else { + $Fnumber = "f/$Fnumber"; + } + $exif_data['Aperture'] = $Fnumber; + + $iso = $exif['ISOSpeedRatings']; + if (!$iso) { + $iso = "N/A"; + } + $exif_data['ISO Speed'] = $iso; + + $Focal = explode("/", $exif['FocalLength']); + if ($Focal[1] != 0) { + $Focal = $Focal[0] / $Focal[1]; + } else { + $Focal = 0; + } + if (!$Focal || round($Focal) == "0") { + $Focal = 0; + } + if (round($Focal) == 0) { + $Focal = "N/A"; + } else { + $Focal = round($Focal) . "mm"; + } + $exif_data['Focal Length'] = $Focal; + + $captured = $exif['DateTime']; + if (!$captured) { + $captured = "N/A"; + } + $exif_data['Captured'] = $captured; + + return $exif_data; +} diff --git a/plugins/tidypics/lib/flickr.php b/plugins/tidypics/lib/flickr.php new file mode 100644 index 0000000000000000000000000000000000000000..effd186c48e00b463d7fc1392c490cae0113a532 --- /dev/null +++ b/plugins/tidypics/lib/flickr.php @@ -0,0 +1,8 @@ +<?php + +function flickr_menu() { + add_submenu_item( elgg_echo( 'flickr:menusetup' ), "/mod/tidypics/pages/flickr/setup.php"); + add_submenu_item( elgg_echo( 'flickr:menuimport' ), "/mod/tidypics/pages/flickr/importPhotosets.php" ); +} + +?> \ No newline at end of file diff --git a/plugins/tidypics/lib/image.php b/plugins/tidypics/lib/image.php new file mode 100644 index 0000000000000000000000000000000000000000..4100f3f7bea31173e3bcdb1557a8e57ed7a624f5 --- /dev/null +++ b/plugins/tidypics/lib/image.php @@ -0,0 +1,179 @@ +<?php +/** + * Tidypics Image class + * + * @package TidypicsImage + */ + + +class TidypicsImage extends ElggFile { + protected function initialise_attributes() { + parent::initialise_attributes(); + + $this->attributes['subtype'] = "image"; + } + + public function __construct($guid = null) { + parent::__construct($guid); + } + + /** + * Has the photo been tagged with "in this photo" tags + * + * @return true/false + */ + public function isPhotoTagged() { + $num_tags = count_annotations($this->getGUID(), 'object', 'image', 'phototag'); + if ($num_tags > 0) { + return true; + } else { + return false; + } + } + + /** + * Get an array of photo tag information + * + * @return array of json representations of the tags and the tag link text + */ + public function getPhotoTags() { + global $CONFIG; + + // get tags as annotations + $photo_tags = get_annotations($this->getGUID(), 'object', 'image', 'phototag'); + if (!$photo_tags) { + // no tags or user doesn't have permission to tags, so return + return false; + } + + $photo_tags_json = "["; + foreach ($photo_tags as $p) { + $photo_tag = unserialize($p->value); + + // create link to page with other photos tagged with same tag + $phototag_text = $photo_tag->value; + $phototag_link = $CONFIG->wwwroot . 'search/?tag=' . $phototag_text . '&subtype=image&object=object'; + if ($photo_tag->type === 'user') { + $user = get_entity($photo_tag->value); + if ($user) { + $phototag_text = $user->name; + } else { + $phototag_text = "unknown user"; + } + + $phototag_link = $CONFIG->wwwroot . "pg/photos/tagged/" . $photo_tag->value; + } + + if (isset($photo_tag->x1)) { + // hack to handle format of Pedro Prez's tags - ugh + $photo_tag->coords = "\"x1\":\"{$photo_tag->x1}\",\"y1\":\"{$photo_tag->y1}\",\"width\":\"{$photo_tag->width}\",\"height\":\"{$photo_tag->height}\""; + $photo_tags_json .= '{' . $photo_tag->coords . ',"text":"' . $phototag_text . '","id":"' . $p->id . '"},'; + } else { + $photo_tags_json .= '{' . $photo_tag->coords . ',"text":"' . $phototag_text . '","id":"' . $p->id . '"},'; + } + + // prepare variable arrays for tagging view + $photo_tag_links[$p->id] = array('text' => $phototag_text, 'url' => $phototag_link); + } + + $photo_tags_json = rtrim($photo_tags_json,','); + $photo_tags_json .= ']'; + + $ret_data = array('json' => $photo_tags_json, 'links' => $photo_tag_links); + return $ret_data; + } + + /** + * Get the view information for this image + * + * @param $viewer_guid the guid of the viewer (0 if not logged in) + * @return array with number of views, number of unique viewers, and number of views for this viewer + */ + public function getViews($viewer_guid) { + $views = get_annotations($this->getGUID(), "object", "image", "tp_view", "", 0, 99999); + if ($views) { + $total_views = count($views); + + if ($this->owner_guid == $viewer_guid) { + // get unique number of viewers + foreach ($views as $view) { + $diff_viewers[$view->owner_guid] = 1; + } + $unique_viewers = count($diff_viewers); + } + else if ($viewer_guid) { + // get the number of times this user has viewed the photo + $my_views = 0; + foreach ($views as $view) { + if ($view->owner_guid == $viewer_guid) { + $my_views++; + } + } + } + + $view_info = array("total" => $total_views, "unique" => $unique_viewers, "mine" => $my_views); + } + else { + $view_info = array("total" => 0, "unique" => 0, "mine" => 0); + } + + return $view_info; + } + + /** + * Add a tidypics view annotation to this image + * + * @param $viewer_guid + * @return none + */ + public function addView($viewer_guid) { + if ($viewer_guid != $this->owner_guid && tp_is_person()) { + create_annotation($this->getGUID(), "tp_view", "1", "integer", $viewer_guid, ACCESS_PUBLIC); + } + } +} + +/** + * get a list of people that can be tagged in an image + * + * @param $viewer entity + * @return array of guid->name for tagging + */ +function tp_get_tag_list($viewer) { + $friends = get_user_friends($viewer->getGUID(), '', 999, 0); + $friend_list = array(); + if ($friends) { + foreach($friends as $friend) { + //error_log("friend $friend->name"); + $friend_list[$friend->guid] = $friend->name; + } + } + + // is this a group + $is_group = tp_is_group_page(); + if ($is_group) { + $group_guid = page_owner(); + $viewer_guid = $viewer->guid; + $members = get_group_members($group_guid, 999); + if (is_array($members)) { + foreach ($members as $member) { + if ($viewer_guid != $member->guid) { + $group_list[$member->guid] = $member->name; + //error_log("group $member->name"); + } + } + + // combine group and friends list + $intersect = array_intersect_key($friend_list, $group_list); + $unique_friends = array_diff_key($friend_list, $group_list); + $unique_members = array_diff_key($group_list, $friend_list); + //$friend_list = array_merge($friend_list, $group_list); + //$friend_list = array_unique($friend_list); + $friend_list = $intersect + $unique_friends + $unique_members; + } + } + + asort($friend_list); + + return $friend_list; +} diff --git a/plugins/tidypics/lib/migrate.php b/plugins/tidypics/lib/migrate.php new file mode 100644 index 0000000000000000000000000000000000000000..f8e68a1be22347d48ae218d1d826c1c3b55e1e47 --- /dev/null +++ b/plugins/tidypics/lib/migrate.php @@ -0,0 +1,299 @@ +<?php +/** + * Tidypics file plugin migration + * + * Supports moving photos from the files plugin to Tidypics. All of a users + * photos end up in a single album. + */ + +// need access to ElggDiskFilestore::make_file_matrix(), which is protected. +// this is a PITA. +class tempFilestore extends ElggDiskFilestore { + public function make_file_matrix($filename) { + return parent::make_file_matrix($filename); + } + +} +$filestore = new tempFilestore(); + + + +/** + * Migrates all pics from files to tidypics. + * + */ +function tidypics_migrate_pics() { + $limit = 100; + $r = true; + + // migrate + // @todo: should this return false since there was no error? + if (!$users = tidypics_get_user_guids_with_pics_in_files(0, $limit)) { + return $r; + } + + //echo "Grabbed " . count($users) . " users\n"; + while (is_array($users) AND count($users) > 0) { + foreach ($users as $user_guid) { + // reset the query cache. + $DB_QUERY_CACHE = array(); + if (!$user = get_entity($user_guid)) { + continue; + } + + $r = tidypics_migrate_user_pics($user); + } + + //echo "Trying to grab $limit more users...\n"; + $offset = $offset + $limit; + $users = tidypics_get_user_guids_with_pics_in_files($offset, $limit); + } + + return $r; +} + + +/** + * Migrates all pictures owned by a user regardless of + * if they're group or user files. + * + * @param ElggUser $user User to migrate. + * @return bool on success + */ +function tidypics_migrate_user_pics(ElggUser $user) { + global $CONFIG, $filestore; + + $user_guid = $user->getGUID(); + + // update all entity subtypes in a single go at the end. + $updated_guids = array(); + + if (!$pics = tidypics_get_user_pics_from_files($user_guid) OR count($pics) < 1) { + return false; + } + + //echo "{$user->name} ({$user->getGUID()}) has " . count($pics) . " pics.\n"; + + // get an album to migrate into if it already exists. + // will create later on if it doesn't. + $user_album_entities = get_entities_from_metadata('migrated_from_files', true, 'object', 'album', $user->getGUID(), 1); + $user_album_guid = isset($album_entities[0]) ? $album_entities[0]->getGUID() : false; + + // a list of albums to randomly select a cover for on newly created albums. + $new_album_guids = array(); + + foreach ($pics as $pic) { + // check that it's not already in tidy pics + if (false !== strpos($pic->filename, 'image/')) { + //echo "{$pic->filename} ({$pic->getGUID()}) looks like it's already in tidy pics. Ignoring.\n"; + continue; + } + + // blank some vars + $group_pic = $group_album_guid = $group_guid = false; + + // see if we're doing a group file migration. + if ($pic->container_guid != $user->getGUID() + AND $group = get_entity($pic->container_guid) + AND $group instanceof ElggGroup + ) { + //echo "{$pic->getGUID()} is in a group!\n"; + $group_pic = true; + $group_guid = $group->getGUID(); + + // yes, this is how you get entities by container_guid. + // yes, it's wrong, wrong, wrong for this function to work this way. + $group_album_entities = get_entities('object', 'album', $group_guid); + + // get_entities_from_metadata doesn't support container_guid (or owner_guid meaning container_guid) + // do it the hard way. + if (is_array($group_album_entities)) { + foreach ($group_album_entities as $group_album) { + if ($group_album->migrated_from_files == true) { + $group_album_guid = $group_album->getGUID(); + break; + } + } + } + $album_guid = $group_album_guid; + $group_album_guids[] = $group_album_guid; + } else { + $album_guid = $user_album_guid; + } + + //echo "album_guid is $album_guid and group_pic is: $group_pic\n"; + + // create an album if we need to. + if (!$album_guid) { + //echo "Creating new album...\n"; + $album = new ElggObject(); + $album->subtype = 'album'; + $album->new_album = TP_NEW_ALBUM; + + if ($group_pic) { + $album->container_guid = $group_guid; + $album->owner_guid = $group->owner_guid; + $album->access_id = $group->group_acl; + $album->title = $group->name; + } else { + $album->container_guid = $user_guid; + $album->owner_guid = $user->getGUID(); + $album->access_id = ACCESS_DEFAULT; + $album->title = $user->name; + } + + if (!$album->save()) { + //echo "Couldn't migrate pics for {$user->name} ($user_guid)!\n"; + return false; + } + $album->migrated_from_files = true; + $album_guid = $album->getGUID(); + $new_album_guids[] = $album_guid; + + // save the album guid as the users + if (!$group_pic) { + $user_album_guid = $album_guid; + } + } + + if (!tidypics_migrate_pic_from_files($pic, $album_guid)) { + //echo "{$pic->filename} ({$pic->getGUID()}) Couldn't be migrated. Ignoring.\n"; + continue; + } + } + + // randomly pic an image to be the cover for the user gallery + //$album->cover = $pic_guids[array_rand($pic_guids)]; + foreach ($new_album_guids as $guid) { + tidypics_set_random_cover_pic($guid); + } + + return true; +} + + +/** + * Randomly pics an image from an album to be the cover. + * @return bool on success + */ +function tidypics_set_random_cover_pic($album_guid) { + global $CONFIG; + + if ($album = get_entity($album_guid) AND $album instanceof TidypicsAlbum) { + $q = "SELECT guid FROM {$CONFIG->dbprefix}entities WHERE container_guid = $album_guid ORDER BY RAND() limit 1"; + $pic = get_data($q); + + return $album->cover = $pic[0]->guid; + } + + return false; +} + +/** + * Migrates a single pic from the file repo. + * @return bool on succes. + */ +function tidypics_migrate_pic_from_files($pic, $album_guid) { + global $CONFIG, $filestore; + + // get the subtype id. + $image_subtype_id = get_subtype_id('object', 'image'); + + // hold which metadata on the files need to be changes + // also holds the images we need to move + $file_md_fields = array('filename', 'thumbnail', 'smallthumb', 'largethumb'); + + if (!$user = get_entity($pic->owner_guid)) { + return false; + } + + // figure out where to move the files. + $matrix = $filestore->make_file_matrix($user->username); + $user_fs_path = $CONFIG->dataroot . $matrix; + $album_fs_path = $CONFIG->dataroot . $matrix . "image/$album_guid/"; + if (!is_dir($album_fs_path)) { + if (!mkdir($album_fs_path, 0700, true)) { + return false; + } + } + + // change all the 'file/'s to 'image/'s in certain metadata + // these are also the files we need to move. + foreach ($file_md_fields as $md_name) { + // $pic->$md_name = str_replace('file/', 'image/', $pic->$md_name); + $old_file = $pic->$md_name; + $new_file = str_replace('file/', "image/$album_guid", $old_file); + + if (!($old_fp = fopen($user_fs_path . $old_file, 'r') + AND $new_fp = fopen($user_fs_path . $new_file, 'w'))) { + //echo "Could not move {$user_fs_path}{$old_file} to {$user_fs_path}{$new_file}\n"; + continue; + } + + while (!feof($old_fp)) { + if (!fputs($new_fp, fread($old_fp, 8192))) { + //echo "Could not move {$user_fs_path}{$old_file} to {$user_fs_path}{$new_file} (Error writing.)\n"; + break; + } + } + + $pic->$md_name = $new_file; + } + // update container. + // this doesn't work...? + //$pic->container_guid = $album_guid; + + // delete old one. + unlink($user_fs_path . $old_file); + + $q = "UPDATE {$CONFIG->dbprefix}entities SET subtype = $image_subtype_id, container_guid = $album_guid WHERE guid = {$pic->getGUID()}"; + //echo "Finished moving {$user_fs_path}{$old_file} to {$user_fs_path}{$new_file}\n"; + + return update_data($q); +} + + +/** + * Grabs all user IDs with images in the files repo. + * return mixed. False on fail, array of GUIDs on success. + */ +function tidypics_get_user_guids_with_pics_in_files($offset, $limit) { + global $CONFIG; + + //$simpletype_ms_id = add_metastring('simple_type'); + //$image_ms_id = add_metastring('image'); + + $q = "SELECT DISTINCT e.owner_guid + FROM + {$CONFIG->dbprefix}entities as e, + {$CONFIG->dbprefix}entity_subtypes as st + + WHERE st.subtype = 'file' + AND e.subtype = st.id + LIMIT $offset, $limit"; + + if (!$data = get_data($q)) { + return false; + } + + // return an array of IDs + $r = array(); + foreach ($data as $row) { + $r[] = $row->owner_guid; + } + + return $r; +} + +/** + * Gets a list of images for a single user. + * @return array of GUIDs, false on fail. + */ +function tidypics_get_user_pics_from_files($user_guid) { + if (!$user = get_entity($user_guid) AND $user instanceof ElggUser) { + return false; + } + + // @todo Might have to cycle this through with standard while + foreach. + return get_entities_from_metadata('simpletype', 'image', 'object', 'file', $user_guid, 5000); +} diff --git a/plugins/tidypics/lib/phpFlickr/PEAR/DB.php b/plugins/tidypics/lib/phpFlickr/PEAR/DB.php new file mode 100644 index 0000000000000000000000000000000000000000..a3eede0705468511c2650a8f542710af97e66a95 --- /dev/null +++ b/plugins/tidypics/lib/phpFlickr/PEAR/DB.php @@ -0,0 +1,1388 @@ +<?php + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * Database independent query interface + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category Database + * @package DB + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V.Cox <cox@idecnet.com> + * @author Daniel Convissor <danielc@php.net> + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: DB.php 32 2005-08-01 06:21:02Z dancoulter $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the PEAR class so it can be extended from + */ +require_once 'PEAR.php'; + + +// {{{ constants +// {{{ error codes + +/**#@+ + * One of PEAR DB's portable error codes. + * @see DB_common::errorCode(), DB::errorMessage() + * + * {@internal If you add an error code here, make sure you also add a textual + * version of it in DB::errorMessage().}} + */ + +/** + * The code returned by many methods upon success + */ +define('DB_OK', 1); + +/** + * Unkown error + */ +define('DB_ERROR', -1); + +/** + * Syntax error + */ +define('DB_ERROR_SYNTAX', -2); + +/** + * Tried to insert a duplicate value into a primary or unique index + */ +define('DB_ERROR_CONSTRAINT', -3); + +/** + * An identifier in the query refers to a non-existant object + */ +define('DB_ERROR_NOT_FOUND', -4); + +/** + * Tried to create a duplicate object + */ +define('DB_ERROR_ALREADY_EXISTS', -5); + +/** + * The current driver does not support the action you attempted + */ +define('DB_ERROR_UNSUPPORTED', -6); + +/** + * The number of parameters does not match the number of placeholders + */ +define('DB_ERROR_MISMATCH', -7); + +/** + * A literal submitted did not match the data type expected + */ +define('DB_ERROR_INVALID', -8); + +/** + * The current DBMS does not support the action you attempted + */ +define('DB_ERROR_NOT_CAPABLE', -9); + +/** + * A literal submitted was too long so the end of it was removed + */ +define('DB_ERROR_TRUNCATED', -10); + +/** + * A literal number submitted did not match the data type expected + */ +define('DB_ERROR_INVALID_NUMBER', -11); + +/** + * A literal date submitted did not match the data type expected + */ +define('DB_ERROR_INVALID_DATE', -12); + +/** + * Attempt to divide something by zero + */ +define('DB_ERROR_DIVZERO', -13); + +/** + * A database needs to be selected + */ +define('DB_ERROR_NODBSELECTED', -14); + +/** + * Could not create the object requested + */ +define('DB_ERROR_CANNOT_CREATE', -15); + +/** + * Could not drop the database requested because it does not exist + */ +define('DB_ERROR_CANNOT_DROP', -17); + +/** + * An identifier in the query refers to a non-existant table + */ +define('DB_ERROR_NOSUCHTABLE', -18); + +/** + * An identifier in the query refers to a non-existant column + */ +define('DB_ERROR_NOSUCHFIELD', -19); + +/** + * The data submitted to the method was inappropriate + */ +define('DB_ERROR_NEED_MORE_DATA', -20); + +/** + * The attempt to lock the table failed + */ +define('DB_ERROR_NOT_LOCKED', -21); + +/** + * The number of columns doesn't match the number of values + */ +define('DB_ERROR_VALUE_COUNT_ON_ROW', -22); + +/** + * The DSN submitted has problems + */ +define('DB_ERROR_INVALID_DSN', -23); + +/** + * Could not connect to the database + */ +define('DB_ERROR_CONNECT_FAILED', -24); + +/** + * The PHP extension needed for this DBMS could not be found + */ +define('DB_ERROR_EXTENSION_NOT_FOUND',-25); + +/** + * The present user has inadequate permissions to perform the task requestd + */ +define('DB_ERROR_ACCESS_VIOLATION', -26); + +/** + * The database requested does not exist + */ +define('DB_ERROR_NOSUCHDB', -27); + +/** + * Tried to insert a null value into a column that doesn't allow nulls + */ +define('DB_ERROR_CONSTRAINT_NOT_NULL',-29); +/**#@-*/ + + +// }}} +// {{{ prepared statement-related + + +/**#@+ + * Identifiers for the placeholders used in prepared statements. + * @see DB_common::prepare() + */ + +/** + * Indicates a scalar (<kbd>?</kbd>) placeholder was used + * + * Quote and escape the value as necessary. + */ +define('DB_PARAM_SCALAR', 1); + +/** + * Indicates an opaque (<kbd>&</kbd>) placeholder was used + * + * The value presented is a file name. Extract the contents of that file + * and place them in this column. + */ +define('DB_PARAM_OPAQUE', 2); + +/** + * Indicates a misc (<kbd>!</kbd>) placeholder was used + * + * The value should not be quoted or escaped. + */ +define('DB_PARAM_MISC', 3); +/**#@-*/ + + +// }}} +// {{{ binary data-related + + +/**#@+ + * The different ways of returning binary data from queries. + */ + +/** + * Sends the fetched data straight through to output + */ +define('DB_BINMODE_PASSTHRU', 1); + +/** + * Lets you return data as usual + */ +define('DB_BINMODE_RETURN', 2); + +/** + * Converts the data to hex format before returning it + * + * For example the string "123" would become "313233". + */ +define('DB_BINMODE_CONVERT', 3); +/**#@-*/ + + +// }}} +// {{{ fetch modes + + +/**#@+ + * Fetch Modes. + * @see DB_common::setFetchMode() + */ + +/** + * Indicates the current default fetch mode should be used + * @see DB_common::$fetchmode + */ +define('DB_FETCHMODE_DEFAULT', 0); + +/** + * Column data indexed by numbers, ordered from 0 and up + */ +define('DB_FETCHMODE_ORDERED', 1); + +/** + * Column data indexed by column names + */ +define('DB_FETCHMODE_ASSOC', 2); + +/** + * Column data as object properties + */ +define('DB_FETCHMODE_OBJECT', 3); + +/** + * For multi-dimensional results, make the column name the first level + * of the array and put the row number in the second level of the array + * + * This is flipped from the normal behavior, which puts the row numbers + * in the first level of the array and the column names in the second level. + */ +define('DB_FETCHMODE_FLIPPED', 4); +/**#@-*/ + +/**#@+ + * Old fetch modes. Left here for compatibility. + */ +define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED); +define('DB_GETMODE_ASSOC', DB_FETCHMODE_ASSOC); +define('DB_GETMODE_FLIPPED', DB_FETCHMODE_FLIPPED); +/**#@-*/ + + +// }}} +// {{{ tableInfo() && autoPrepare()-related + + +/**#@+ + * The type of information to return from the tableInfo() method. + * + * Bitwised constants, so they can be combined using <kbd>|</kbd> + * and removed using <kbd>^</kbd>. + * + * @see DB_common::tableInfo() + * + * {@internal Since the TABLEINFO constants are bitwised, if more of them are + * added in the future, make sure to adjust DB_TABLEINFO_FULL accordingly.}} + */ +define('DB_TABLEINFO_ORDER', 1); +define('DB_TABLEINFO_ORDERTABLE', 2); +define('DB_TABLEINFO_FULL', 3); +/**#@-*/ + + +/**#@+ + * The type of query to create with the automatic query building methods. + * @see DB_common::autoPrepare(), DB_common::autoExecute() + */ +define('DB_AUTOQUERY_INSERT', 1); +define('DB_AUTOQUERY_UPDATE', 2); +/**#@-*/ + + +// }}} +// {{{ portability modes + + +/**#@+ + * Portability Modes. + * + * Bitwised constants, so they can be combined using <kbd>|</kbd> + * and removed using <kbd>^</kbd>. + * + * @see DB_common::setOption() + * + * {@internal Since the PORTABILITY constants are bitwised, if more of them are + * added in the future, make sure to adjust DB_PORTABILITY_ALL accordingly.}} + */ + +/** + * Turn off all portability features + */ +define('DB_PORTABILITY_NONE', 0); + +/** + * Convert names of tables and fields to lower case + * when using the get*(), fetch*() and tableInfo() methods + */ +define('DB_PORTABILITY_LOWERCASE', 1); + +/** + * Right trim the data output by get*() and fetch*() + */ +define('DB_PORTABILITY_RTRIM', 2); + +/** + * Force reporting the number of rows deleted + */ +define('DB_PORTABILITY_DELETE_COUNT', 4); + +/** + * Enable hack that makes numRows() work in Oracle + */ +define('DB_PORTABILITY_NUMROWS', 8); + +/** + * Makes certain error messages in certain drivers compatible + * with those from other DBMS's + * + * + mysql, mysqli: change unique/primary key constraints + * DB_ERROR_ALREADY_EXISTS -> DB_ERROR_CONSTRAINT + * + * + odbc(access): MS's ODBC driver reports 'no such field' as code + * 07001, which means 'too few parameters.' When this option is on + * that code gets mapped to DB_ERROR_NOSUCHFIELD. + */ +define('DB_PORTABILITY_ERRORS', 16); + +/** + * Convert null values to empty strings in data output by + * get*() and fetch*() + */ +define('DB_PORTABILITY_NULL_TO_EMPTY', 32); + +/** + * Turn on all portability features + */ +define('DB_PORTABILITY_ALL', 63); +/**#@-*/ + +// }}} + + +// }}} +// {{{ class DB + +/** + * Database independent query interface + * + * The main "DB" class is simply a container class with some static + * methods for creating DB objects as well as some utility functions + * common to all parts of DB. + * + * The object model of DB is as follows (indentation means inheritance): + * <pre> + * DB The main DB class. This is simply a utility class + * with some "static" methods for creating DB objects as + * well as common utility functions for other DB classes. + * + * DB_common The base for each DB implementation. Provides default + * | implementations (in OO lingo virtual methods) for + * | the actual DB implementations as well as a bunch of + * | query utility functions. + * | + * +-DB_mysql The DB implementation for MySQL. Inherits DB_common. + * When calling DB::factory or DB::connect for MySQL + * connections, the object returned is an instance of this + * class. + * </pre> + * + * @category Database + * @package DB + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V.Cox <cox@idecnet.com> + * @author Daniel Convissor <danielc@php.net> + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB +{ + // {{{ &factory() + + /** + * Create a new DB object for the specified database type but don't + * connect to the database + * + * @param string $type the database type (eg "mysql") + * @param array $options an associative array of option names and values + * + * @return object a new DB object. A DB_Error object on failure. + * + * @see DB_common::setOption() + */ + function &factory($type, $options = false) + { + if (!is_array($options)) { + $options = array('persistent' => $options); + } + + if (isset($options['debug']) && $options['debug'] >= 2) { + // expose php errors with sufficient debug level + include_once "DB/{$type}.php"; + } else { + @include_once "DB/{$type}.php"; + } + + $classname = "DB_${type}"; + + if (!class_exists($classname)) { + $tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null, + "Unable to include the DB/{$type}.php" + . " file for '$dsn'", + 'DB_Error', true); + return $tmp; + } + + @$obj =& new $classname; + + foreach ($options as $option => $value) { + $test = $obj->setOption($option, $value); + if (DB::isError($test)) { + return $test; + } + } + + return $obj; + } + + // }}} + // {{{ &connect() + + /** + * Create a new DB object including a connection to the specified database + * + * Example 1. + * <code> + * require_once 'DB.php'; + * + * $dsn = 'pgsql://user:password@host/database'; + * $options = array( + * 'debug' => 2, + * 'portability' => DB_PORTABILITY_ALL, + * ); + * + * $db =& DB::connect($dsn, $options); + * if (PEAR::isError($db)) { + * die($db->getMessage()); + * } + * </code> + * + * @param mixed $dsn the string "data source name" or array in the + * format returned by DB::parseDSN() + * @param array $options an associative array of option names and values + * + * @return object a new DB object. A DB_Error object on failure. + * + * @uses DB_dbase::connect(), DB_fbsql::connect(), DB_ibase::connect(), + * DB_ifx::connect(), DB_msql::connect(), DB_mssql::connect(), + * DB_mysql::connect(), DB_mysqli::connect(), DB_oci8::connect(), + * DB_odbc::connect(), DB_pgsql::connect(), DB_sqlite::connect(), + * DB_sybase::connect() + * + * @uses DB::parseDSN(), DB_common::setOption(), PEAR::isError() + */ + function &connect($dsn, $options = array()) + { + $dsninfo = DB::parseDSN($dsn); + $type = $dsninfo['phptype']; + + if (!is_array($options)) { + /* + * For backwards compatibility. $options used to be boolean, + * indicating whether the connection should be persistent. + */ + $options = array('persistent' => $options); + } + + if (isset($options['debug']) && $options['debug'] >= 2) { + // expose php errors with sufficient debug level + include_once "DB/${type}.php"; + } else { + @include_once "DB/${type}.php"; + } + + $classname = "DB_${type}"; + if (!class_exists($classname)) { + $tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null, + "Unable to include the DB/{$type}.php" + . " file for '$dsn'", + 'DB_Error', true); + return $tmp; + } + + @$obj =& new $classname; + + foreach ($options as $option => $value) { + $test = $obj->setOption($option, $value); + if (DB::isError($test)) { + return $test; + } + } + + $err = $obj->connect($dsninfo, $obj->getOption('persistent')); + if (DB::isError($err)) { + $err->addUserInfo($dsn); + return $err; + } + + return $obj; + } + + // }}} + // {{{ apiVersion() + + /** + * Return the DB API version + * + * @return string the DB API version number + */ + function apiVersion() + { + return '@package_version@'; + } + + // }}} + // {{{ isError() + + /** + * Determines if a variable is a DB_Error object + * + * @param mixed $value the variable to check + * + * @return bool whether $value is DB_Error object + */ + function isError($value) + { + return is_a($value, 'DB_Error'); + } + + // }}} + // {{{ isConnection() + + /** + * Determines if a value is a DB_<driver> object + * + * @param mixed $value the value to test + * + * @return bool whether $value is a DB_<driver> object + */ + function isConnection($value) + { + return (is_object($value) && + is_subclass_of($value, 'db_common') && + method_exists($value, 'simpleQuery')); + } + + // }}} + // {{{ isManip() + + /** + * Tell whether a query is a data manipulation or data definition query + * + * Examples of data manipulation queries are INSERT, UPDATE and DELETE. + * Examples of data definition queries are CREATE, DROP, ALTER, GRANT, + * REVOKE. + * + * @param string $query the query + * + * @return boolean whether $query is a data manipulation query + */ + function isManip($query) + { + $manips = 'INSERT|UPDATE|DELETE|REPLACE|' + . 'CREATE|DROP|' + . 'LOAD DATA|SELECT .* INTO|COPY|' + . 'ALTER|GRANT|REVOKE|' + . 'LOCK|UNLOCK'; + if (preg_match('/^\s*"?(' . $manips . ')\s+/i', $query)) { + return true; + } + return false; + } + + // }}} + // {{{ errorMessage() + + /** + * Return a textual error message for a DB error code + * + * @param integer $value the DB error code + * + * @return string the error message or false if the error code was + * not recognized + */ + function errorMessage($value) + { + static $errorMessages; + if (!isset($errorMessages)) { + $errorMessages = array( + DB_ERROR => 'unknown error', + DB_ERROR_ACCESS_VIOLATION => 'insufficient permissions', + DB_ERROR_ALREADY_EXISTS => 'already exists', + DB_ERROR_CANNOT_CREATE => 'can not create', + DB_ERROR_CANNOT_DROP => 'can not drop', + DB_ERROR_CONNECT_FAILED => 'connect failed', + DB_ERROR_CONSTRAINT => 'constraint violation', + DB_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint', + DB_ERROR_DIVZERO => 'division by zero', + DB_ERROR_EXTENSION_NOT_FOUND=> 'extension not found', + DB_ERROR_INVALID => 'invalid', + DB_ERROR_INVALID_DATE => 'invalid date or time', + DB_ERROR_INVALID_DSN => 'invalid DSN', + DB_ERROR_INVALID_NUMBER => 'invalid number', + DB_ERROR_MISMATCH => 'mismatch', + DB_ERROR_NEED_MORE_DATA => 'insufficient data supplied', + DB_ERROR_NODBSELECTED => 'no database selected', + DB_ERROR_NOSUCHDB => 'no such database', + DB_ERROR_NOSUCHFIELD => 'no such field', + DB_ERROR_NOSUCHTABLE => 'no such table', + DB_ERROR_NOT_CAPABLE => 'DB backend not capable', + DB_ERROR_NOT_FOUND => 'not found', + DB_ERROR_NOT_LOCKED => 'not locked', + DB_ERROR_SYNTAX => 'syntax error', + DB_ERROR_UNSUPPORTED => 'not supported', + DB_ERROR_TRUNCATED => 'truncated', + DB_ERROR_VALUE_COUNT_ON_ROW => 'value count on row', + DB_OK => 'no error', + ); + } + + if (DB::isError($value)) { + $value = $value->getCode(); + } + + return isset($errorMessages[$value]) ? $errorMessages[$value] + : $errorMessages[DB_ERROR]; + } + + // }}} + // {{{ parseDSN() + + /** + * Parse a data source name + * + * Additional keys can be added by appending a URI query string to the + * end of the DSN. + * + * The format of the supplied DSN is in its fullest form: + * <code> + * phptype(dbsyntax)://username:password@protocol+hostspec/database?option=8&another=true + * </code> + * + * Most variations are allowed: + * <code> + * phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644 + * phptype://username:password@hostspec/database_name + * phptype://username:password@hostspec + * phptype://username@hostspec + * phptype://hostspec/database + * phptype://hostspec + * phptype(dbsyntax) + * phptype + * </code> + * + * @param string $dsn Data Source Name to be parsed + * + * @return array an associative array with the following keys: + * + phptype: Database backend used in PHP (mysql, odbc etc.) + * + dbsyntax: Database used with regards to SQL syntax etc. + * + protocol: Communication protocol to use (tcp, unix etc.) + * + hostspec: Host specification (hostname[:port]) + * + database: Database to use on the DBMS server + * + username: User name for login + * + password: Password for login + */ + function parseDSN($dsn) + { + $parsed = array( + 'phptype' => false, + 'dbsyntax' => false, + 'username' => false, + 'password' => false, + 'protocol' => false, + 'hostspec' => false, + 'port' => false, + 'socket' => false, + 'database' => false, + ); + + if (is_array($dsn)) { + $dsn = array_merge($parsed, $dsn); + if (!$dsn['dbsyntax']) { + $dsn['dbsyntax'] = $dsn['phptype']; + } + return $dsn; + } + + // Find phptype and dbsyntax + if (($pos = strpos($dsn, '://')) !== false) { + $str = substr($dsn, 0, $pos); + $dsn = substr($dsn, $pos + 3); + } else { + $str = $dsn; + $dsn = null; + } + + // Get phptype and dbsyntax + // $str => phptype(dbsyntax) + if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) { + $parsed['phptype'] = $arr[1]; + $parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2]; + } else { + $parsed['phptype'] = $str; + $parsed['dbsyntax'] = $str; + } + + if (!count($dsn)) { + return $parsed; + } + + // Get (if found): username and password + // $dsn => username:password@protocol+hostspec/database + if (($at = strrpos($dsn,'@')) !== false) { + $str = substr($dsn, 0, $at); + $dsn = substr($dsn, $at + 1); + if (($pos = strpos($str, ':')) !== false) { + $parsed['username'] = rawurldecode(substr($str, 0, $pos)); + $parsed['password'] = rawurldecode(substr($str, $pos + 1)); + } else { + $parsed['username'] = rawurldecode($str); + } + } + + // Find protocol and hostspec + + if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) { + // $dsn => proto(proto_opts)/database + $proto = $match[1]; + $proto_opts = $match[2] ? $match[2] : false; + $dsn = $match[3]; + + } else { + // $dsn => protocol+hostspec/database (old format) + if (strpos($dsn, '+') !== false) { + list($proto, $dsn) = explode('+', $dsn, 2); + } + if (strpos($dsn, '/') !== false) { + list($proto_opts, $dsn) = explode('/', $dsn, 2); + } else { + $proto_opts = $dsn; + $dsn = null; + } + } + + // process the different protocol options + $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp'; + $proto_opts = rawurldecode($proto_opts); + if ($parsed['protocol'] == 'tcp') { + if (strpos($proto_opts, ':') !== false) { + list($parsed['hostspec'], + $parsed['port']) = explode(':', $proto_opts); + } else { + $parsed['hostspec'] = $proto_opts; + } + } elseif ($parsed['protocol'] == 'unix') { + $parsed['socket'] = $proto_opts; + } + + // Get dabase if any + // $dsn => database + if ($dsn) { + if (($pos = strpos($dsn, '?')) === false) { + // /database + $parsed['database'] = rawurldecode($dsn); + } else { + // /database?param1=value1¶m2=value2 + $parsed['database'] = rawurldecode(substr($dsn, 0, $pos)); + $dsn = substr($dsn, $pos + 1); + if (strpos($dsn, '&') !== false) { + $opts = explode('&', $dsn); + } else { // database?param1=value1 + $opts = array($dsn); + } + foreach ($opts as $opt) { + list($key, $value) = explode('=', $opt); + if (!isset($parsed[$key])) { + // don't allow params overwrite + $parsed[$key] = rawurldecode($value); + } + } + } + } + + return $parsed; + } + + // }}} +} + +// }}} +// {{{ class DB_Error + +/** + * DB_Error implements a class for reporting portable database error + * messages + * + * @category Database + * @package DB + * @author Stig Bakken <ssb@php.net> + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_Error extends PEAR_Error +{ + // {{{ constructor + + /** + * DB_Error constructor + * + * @param mixed $code DB error code, or string with error message + * @param int $mode what "error mode" to operate in + * @param int $level what error level to use for $mode & + * PEAR_ERROR_TRIGGER + * @param mixed $debuginfo additional debug info, such as the last query + * + * @see PEAR_Error + */ + function DB_Error($code = DB_ERROR, $mode = PEAR_ERROR_RETURN, + $level = E_USER_NOTICE, $debuginfo = null) + { + if (is_int($code)) { + $this->PEAR_Error('DB Error: ' . DB::errorMessage($code), $code, + $mode, $level, $debuginfo); + } else { + $this->PEAR_Error("DB Error: $code", DB_ERROR, + $mode, $level, $debuginfo); + } + } + + // }}} +} + +// }}} +// {{{ class DB_result + +/** + * This class implements a wrapper for a DB result set + * + * A new instance of this class will be returned by the DB implementation + * after processing a query that returns data. + * + * @category Database + * @package DB + * @author Stig Bakken <ssb@php.net> + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_result +{ + // {{{ properties + + /** + * Should results be freed automatically when there are no more rows? + * @var boolean + * @see DB_common::$options + */ + var $autofree; + + /** + * A reference to the DB_<driver> object + * @var object + */ + var $dbh; + + /** + * The current default fetch mode + * @var integer + * @see DB_common::$fetchmode + */ + var $fetchmode; + + /** + * The name of the class into which results should be fetched when + * DB_FETCHMODE_OBJECT is in effect + * + * @var string + * @see DB_common::$fetchmode_object_class + */ + var $fetchmode_object_class; + + /** + * The number of rows to fetch from a limit query + * @var integer + */ + var $limit_count = null; + + /** + * The row to start fetching from in limit queries + * @var integer + */ + var $limit_from = null; + + /** + * The execute parameters that created this result + * @var array + * @since Property available since Release 1.7.0 + */ + var $parameters; + + /** + * The query string that created this result + * + * Copied here incase it changes in $dbh, which is referenced + * + * @var string + * @since Property available since Release 1.7.0 + */ + var $query; + + /** + * The query result resource id created by PHP + * @var resource + */ + var $result; + + /** + * The present row being dealt with + * @var integer + */ + var $row_counter = null; + + /** + * The prepared statement resource id created by PHP in $dbh + * + * This resource is only available when the result set was created using + * a driver's native execute() method, not PEAR DB's emulated one. + * + * Copied here incase it changes in $dbh, which is referenced + * + * {@internal Mainly here because the InterBase/Firebird API is only + * able to retrieve data from result sets if the statemnt handle is + * still in scope.}} + * + * @var resource + * @since Property available since Release 1.7.0 + */ + var $statement; + + + // }}} + // {{{ constructor + + /** + * This constructor sets the object's properties + * + * @param object &$dbh the DB object reference + * @param resource $result the result resource id + * @param array $options an associative array with result options + * + * @return void + */ + function DB_result(&$dbh, $result, $options = array()) + { + $this->autofree = $dbh->options['autofree']; + $this->dbh = &$dbh; + $this->fetchmode = $dbh->fetchmode; + $this->fetchmode_object_class = $dbh->fetchmode_object_class; + $this->parameters = $dbh->last_parameters; + $this->query = $dbh->last_query; + $this->result = $result; + $this->statement = empty($dbh->last_stmt) ? null : $dbh->last_stmt; + foreach ($options as $key => $value) { + $this->setOption($key, $value); + } + } + + /** + * Set options for the DB_result object + * + * @param string $key the option to set + * @param mixed $value the value to set the option to + * + * @return void + */ + function setOption($key, $value = null) + { + switch ($key) { + case 'limit_from': + $this->limit_from = $value; + break; + case 'limit_count': + $this->limit_count = $value; + } + } + + // }}} + // {{{ fetchRow() + + /** + * Fetch a row of data and return it by reference into an array + * + * The type of array returned can be controlled either by setting this + * method's <var>$fetchmode</var> parameter or by changing the default + * fetch mode setFetchMode() before calling this method. + * + * There are two options for standardizing the information returned + * from databases, ensuring their values are consistent when changing + * DBMS's. These portability options can be turned on when creating a + * new DB object or by using setOption(). + * + * + <var>DB_PORTABILITY_LOWERCASE</var> + * convert names of fields to lower case + * + * + <var>DB_PORTABILITY_RTRIM</var> + * right trim the data + * + * @param int $fetchmode the constant indicating how to format the data + * @param int $rownum the row number to fetch (index starts at 0) + * + * @return mixed an array or object containing the row's data, + * NULL when the end of the result set is reached + * or a DB_Error object on failure. + * + * @see DB_common::setOption(), DB_common::setFetchMode() + */ + function &fetchRow($fetchmode = DB_FETCHMODE_DEFAULT, $rownum = null) + { + if ($fetchmode === DB_FETCHMODE_DEFAULT) { + $fetchmode = $this->fetchmode; + } + if ($fetchmode === DB_FETCHMODE_OBJECT) { + $fetchmode = DB_FETCHMODE_ASSOC; + $object_class = $this->fetchmode_object_class; + } + if ($this->limit_from !== null) { + if ($this->row_counter === null) { + $this->row_counter = $this->limit_from; + // Skip rows + if ($this->dbh->features['limit'] === false) { + $i = 0; + while ($i++ < $this->limit_from) { + $this->dbh->fetchInto($this->result, $arr, $fetchmode); + } + } + } + if ($this->row_counter >= ($this->limit_from + $this->limit_count)) + { + if ($this->autofree) { + $this->free(); + } + $tmp = null; + return $tmp; + } + if ($this->dbh->features['limit'] === 'emulate') { + $rownum = $this->row_counter; + } + $this->row_counter++; + } + $res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum); + if ($res === DB_OK) { + if (isset($object_class)) { + // The default mode is specified in the + // DB_common::fetchmode_object_class property + if ($object_class == 'stdClass') { + $arr = (object) $arr; + } else { + $arr = &new $object_class($arr); + } + } + return $arr; + } + if ($res == null && $this->autofree) { + $this->free(); + } + return $res; + } + + // }}} + // {{{ fetchInto() + + /** + * Fetch a row of data into an array which is passed by reference + * + * The type of array returned can be controlled either by setting this + * method's <var>$fetchmode</var> parameter or by changing the default + * fetch mode setFetchMode() before calling this method. + * + * There are two options for standardizing the information returned + * from databases, ensuring their values are consistent when changing + * DBMS's. These portability options can be turned on when creating a + * new DB object or by using setOption(). + * + * + <var>DB_PORTABILITY_LOWERCASE</var> + * convert names of fields to lower case + * + * + <var>DB_PORTABILITY_RTRIM</var> + * right trim the data + * + * @param array &$arr the variable where the data should be placed + * @param int $fetchmode the constant indicating how to format the data + * @param int $rownum the row number to fetch (index starts at 0) + * + * @return mixed DB_OK if a row is processed, NULL when the end of the + * result set is reached or a DB_Error object on failure + * + * @see DB_common::setOption(), DB_common::setFetchMode() + */ + function fetchInto(&$arr, $fetchmode = DB_FETCHMODE_DEFAULT, $rownum = null) + { + if ($fetchmode === DB_FETCHMODE_DEFAULT) { + $fetchmode = $this->fetchmode; + } + if ($fetchmode === DB_FETCHMODE_OBJECT) { + $fetchmode = DB_FETCHMODE_ASSOC; + $object_class = $this->fetchmode_object_class; + } + if ($this->limit_from !== null) { + if ($this->row_counter === null) { + $this->row_counter = $this->limit_from; + // Skip rows + if ($this->dbh->features['limit'] === false) { + $i = 0; + while ($i++ < $this->limit_from) { + $this->dbh->fetchInto($this->result, $arr, $fetchmode); + } + } + } + if ($this->row_counter >= ( + $this->limit_from + $this->limit_count)) + { + if ($this->autofree) { + $this->free(); + } + return null; + } + if ($this->dbh->features['limit'] === 'emulate') { + $rownum = $this->row_counter; + } + + $this->row_counter++; + } + $res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum); + if ($res === DB_OK) { + if (isset($object_class)) { + // default mode specified in the + // DB_common::fetchmode_object_class property + if ($object_class == 'stdClass') { + $arr = (object) $arr; + } else { + $arr = new $object_class($arr); + } + } + return DB_OK; + } + if ($res == null && $this->autofree) { + $this->free(); + } + return $res; + } + + // }}} + // {{{ numCols() + + /** + * Get the the number of columns in a result set + * + * @return int the number of columns. A DB_Error object on failure. + */ + function numCols() + { + return $this->dbh->numCols($this->result); + } + + // }}} + // {{{ numRows() + + /** + * Get the number of rows in a result set + * + * @return int the number of rows. A DB_Error object on failure. + */ + function numRows() + { + if ($this->dbh->features['numrows'] === 'emulate' + && $this->dbh->options['portability'] & DB_PORTABILITY_NUMROWS) + { + if ($this->dbh->features['prepare']) { + $res = $this->dbh->query($this->query, $this->parameters); + } else { + $res = $this->dbh->query($this->query); + } + if (DB::isError($res)) { + return $res; + } + $i = 0; + while ($res->fetchInto($tmp, DB_FETCHMODE_ORDERED)) { + $i++; + } + return $i; + } else { + return $this->dbh->numRows($this->result); + } + } + + // }}} + // {{{ nextResult() + + /** + * Get the next result if a batch of queries was executed + * + * @return bool true if a new result is available or false if not + */ + function nextResult() + { + return $this->dbh->nextResult($this->result); + } + + // }}} + // {{{ free() + + /** + * Frees the resources allocated for this result set + * + * @return bool true on success. A DB_Error object on failure. + */ + function free() + { + $err = $this->dbh->freeResult($this->result); + if (DB::isError($err)) { + return $err; + } + $this->result = false; + $this->statement = false; + return true; + } + + // }}} + // {{{ tableInfo() + + /** + * @see DB_common::tableInfo() + * @deprecated Method deprecated some time before Release 1.2 + */ + function tableInfo($mode = null) + { + if (is_string($mode)) { + return $this->dbh->raiseError(DB_ERROR_NEED_MORE_DATA); + } + return $this->dbh->tableInfo($this, $mode); + } + + // }}} + // {{{ getQuery() + + /** + * Determine the query string that created this result + * + * @return string the query string + * + * @since Method available since Release 1.7.0 + */ + function getQuery() + { + return $this->query; + } + + // }}} + // {{{ getRowCounter() + + /** + * Tells which row number is currently being processed + * + * @return integer the current row being looked at. Starts at 1. + */ + function getRowCounter() + { + return $this->row_counter; + } + + // }}} +} + +// }}} +// {{{ class DB_row + +/** + * PEAR DB Row Object + * + * The object contains a row of data from a result set. Each column's data + * is placed in a property named for the column. + * + * @category Database + * @package DB + * @author Stig Bakken <ssb@php.net> + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + * @see DB_common::setFetchMode() + */ +class DB_row +{ + // {{{ constructor + + /** + * The constructor places a row's data into properties of this object + * + * @param array the array containing the row's data + * + * @return void + */ + function DB_row(&$arr) + { + foreach ($arr as $key => $value) { + $this->$key = &$arr[$key]; + } + } + + // }}} +} + +// }}} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/plugins/tidypics/lib/phpFlickr/PEAR/DB/common.php b/plugins/tidypics/lib/phpFlickr/PEAR/DB/common.php new file mode 100644 index 0000000000000000000000000000000000000000..04e71ff52b4427c8adb77bc9971d47327b1181eb --- /dev/null +++ b/plugins/tidypics/lib/phpFlickr/PEAR/DB/common.php @@ -0,0 +1,2157 @@ +<?php + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * Contains the DB_common base class + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category Database + * @package DB + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V. Cox <cox@idecnet.com> + * @author Daniel Convissor <danielc@php.net> + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: common.php 32 2005-08-01 06:21:02Z dancoulter $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the PEAR class so it can be extended from + */ +require_once 'PEAR.php'; + +/** + * DB_common is the base class from which each database driver class extends + * + * All common methods are declared here. If a given DBMS driver contains + * a particular method, that method will overload the one here. + * + * @category Database + * @package DB + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V. Cox <cox@idecnet.com> + * @author Daniel Convissor <danielc@php.net> + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_common extends PEAR +{ + // {{{ properties + + /** + * The current default fetch mode + * @var integer + */ + var $fetchmode = DB_FETCHMODE_ORDERED; + + /** + * The name of the class into which results should be fetched when + * DB_FETCHMODE_OBJECT is in effect + * + * @var string + */ + var $fetchmode_object_class = 'stdClass'; + + /** + * Was a connection present when the object was serialized()? + * @var bool + * @see DB_common::__sleep(), DB_common::__wake() + */ + var $was_connected = null; + + /** + * The most recently executed query + * @var string + */ + var $last_query = ''; + + /** + * Run-time configuration options + * + * The 'optimize' option has been deprecated. Use the 'portability' + * option instead. + * + * @var array + * @see DB_common::setOption() + */ + var $options = array( + 'result_buffering' => 500, + 'persistent' => false, + 'ssl' => false, + 'debug' => 0, + 'seqname_format' => '%s_seq', + 'autofree' => false, + 'portability' => DB_PORTABILITY_NONE, + 'optimize' => 'performance', // Deprecated. Use 'portability'. + ); + + /** + * The parameters from the most recently executed query + * @var array + * @since Property available since Release 1.7.0 + */ + var $last_parameters = array(); + + /** + * The elements from each prepared statement + * @var array + */ + var $prepare_tokens = array(); + + /** + * The data types of the various elements in each prepared statement + * @var array + */ + var $prepare_types = array(); + + /** + * The prepared queries + * @var array + */ + var $prepared_queries = array(); + + + // }}} + // {{{ DB_common + + /** + * This constructor calls <kbd>$this->PEAR('DB_Error')</kbd> + * + * @return void + */ + function DB_common() + { + $this->PEAR('DB_Error'); + } + + // }}} + // {{{ __sleep() + + /** + * Automatically indicates which properties should be saved + * when PHP's serialize() function is called + * + * @return array the array of properties names that should be saved + */ + function __sleep() + { + if ($this->connection) { + // Don't disconnect(), people use serialize() for many reasons + $this->was_connected = true; + } else { + $this->was_connected = false; + } + if (isset($this->autocommit)) { + return array('autocommit', + 'dbsyntax', + 'dsn', + 'features', + 'fetchmode', + 'fetchmode_object_class', + 'options', + 'was_connected', + ); + } else { + return array('dbsyntax', + 'dsn', + 'features', + 'fetchmode', + 'fetchmode_object_class', + 'options', + 'was_connected', + ); + } + } + + // }}} + // {{{ __wakeup() + + /** + * Automatically reconnects to the database when PHP's unserialize() + * function is called + * + * The reconnection attempt is only performed if the object was connected + * at the time PHP's serialize() function was run. + * + * @return void + */ + function __wakeup() + { + if ($this->was_connected) { + $this->connect($this->dsn, $this->options); + } + } + + // }}} + // {{{ __toString() + + /** + * Automatic string conversion for PHP 5 + * + * @return string a string describing the current PEAR DB object + * + * @since Method available since Release 1.7.0 + */ + function __toString() + { + $info = strtolower(get_class($this)); + $info .= ': (phptype=' . $this->phptype . + ', dbsyntax=' . $this->dbsyntax . + ')'; + if ($this->connection) { + $info .= ' [connected]'; + } + return $info; + } + + // }}} + // {{{ toString() + + /** + * DEPRECATED: String conversion method + * + * @return string a string describing the current PEAR DB object + * + * @deprecated Method deprecated in Release 1.7.0 + */ + function toString() + { + return $this->__toString(); + } + + // }}} + // {{{ quoteString() + + /** + * DEPRECATED: Quotes a string so it can be safely used within string + * delimiters in a query + * + * @param string $string the string to be quoted + * + * @return string the quoted string + * + * @see DB_common::quoteSmart(), DB_common::escapeSimple() + * @deprecated Method deprecated some time before Release 1.2 + */ + function quoteString($string) + { + $string = $this->quote($string); + if ($string{0} == "'") { + return substr($string, 1, -1); + } + return $string; + } + + // }}} + // {{{ quote() + + /** + * DEPRECATED: Quotes a string so it can be safely used in a query + * + * @param string $string the string to quote + * + * @return string the quoted string or the string <samp>NULL</samp> + * if the value submitted is <kbd>null</kbd>. + * + * @see DB_common::quoteSmart(), DB_common::escapeSimple() + * @deprecated Deprecated in release 1.6.0 + */ + function quote($string = null) + { + return ($string === null) ? 'NULL' + : "'" . str_replace("'", "''", $string) . "'"; + } + + // }}} + // {{{ quoteIdentifier() + + /** + * Quotes a string so it can be safely used as a table or column name + * + * Delimiting style depends on which database driver is being used. + * + * NOTE: just because you CAN use delimited identifiers doesn't mean + * you SHOULD use them. In general, they end up causing way more + * problems than they solve. + * + * Portability is broken by using the following characters inside + * delimited identifiers: + * + backtick (<kbd>`</kbd>) -- due to MySQL + * + double quote (<kbd>"</kbd>) -- due to Oracle + * + brackets (<kbd>[</kbd> or <kbd>]</kbd>) -- due to Access + * + * Delimited identifiers are known to generally work correctly under + * the following drivers: + * + mssql + * + mysql + * + mysqli + * + oci8 + * + odbc(access) + * + odbc(db2) + * + pgsql + * + sqlite + * + sybase (must execute <kbd>set quoted_identifier on</kbd> sometime + * prior to use) + * + * InterBase doesn't seem to be able to use delimited identifiers + * via PHP 4. They work fine under PHP 5. + * + * @param string $str the identifier name to be quoted + * + * @return string the quoted identifier + * + * @since Method available since Release 1.6.0 + */ + function quoteIdentifier($str) + { + return '"' . str_replace('"', '""', $str) . '"'; + } + + // }}} + // {{{ quoteSmart() + + /** + * Formats input so it can be safely used in a query + * + * The output depends on the PHP data type of input and the database + * type being used. + * + * @param mixed $in the data to be formatted + * + * @return mixed the formatted data. The format depends on the input's + * PHP type: + * <ul> + * <li> + * <kbd>input</kbd> -> <samp>returns</samp> + * </li> + * <li> + * <kbd>null</kbd> -> the string <samp>NULL</samp> + * </li> + * <li> + * <kbd>integer</kbd> or <kbd>double</kbd> -> the unquoted number + * </li> + * <li> + * <kbd>bool</kbd> -> output depends on the driver in use + * Most drivers return integers: <samp>1</samp> if + * <kbd>true</kbd> or <samp>0</samp> if + * <kbd>false</kbd>. + * Some return strings: <samp>TRUE</samp> if + * <kbd>true</kbd> or <samp>FALSE</samp> if + * <kbd>false</kbd>. + * Finally one returns strings: <samp>T</samp> if + * <kbd>true</kbd> or <samp>F</samp> if + * <kbd>false</kbd>. Here is a list of each DBMS, + * the values returned and the suggested column type: + * <ul> + * <li> + * <kbd>dbase</kbd> -> <samp>T/F</samp> + * (<kbd>Logical</kbd>) + * </li> + * <li> + * <kbd>fbase</kbd> -> <samp>TRUE/FALSE</samp> + * (<kbd>BOOLEAN</kbd>) + * </li> + * <li> + * <kbd>ibase</kbd> -> <samp>1/0</samp> + * (<kbd>SMALLINT</kbd>) [1] + * </li> + * <li> + * <kbd>ifx</kbd> -> <samp>1/0</samp> + * (<kbd>SMALLINT</kbd>) [1] + * </li> + * <li> + * <kbd>msql</kbd> -> <samp>1/0</samp> + * (<kbd>INTEGER</kbd>) + * </li> + * <li> + * <kbd>mssql</kbd> -> <samp>1/0</samp> + * (<kbd>BIT</kbd>) + * </li> + * <li> + * <kbd>mysql</kbd> -> <samp>1/0</samp> + * (<kbd>TINYINT(1)</kbd>) + * </li> + * <li> + * <kbd>mysqli</kbd> -> <samp>1/0</samp> + * (<kbd>TINYINT(1)</kbd>) + * </li> + * <li> + * <kbd>oci8</kbd> -> <samp>1/0</samp> + * (<kbd>NUMBER(1)</kbd>) + * </li> + * <li> + * <kbd>odbc</kbd> -> <samp>1/0</samp> + * (<kbd>SMALLINT</kbd>) [1] + * </li> + * <li> + * <kbd>pgsql</kbd> -> <samp>TRUE/FALSE</samp> + * (<kbd>BOOLEAN</kbd>) + * </li> + * <li> + * <kbd>sqlite</kbd> -> <samp>1/0</samp> + * (<kbd>INTEGER</kbd>) + * </li> + * <li> + * <kbd>sybase</kbd> -> <samp>1/0</samp> + * (<kbd>TINYINT(1)</kbd>) + * </li> + * </ul> + * [1] Accommodate the lowest common denominator because not all + * versions of have <kbd>BOOLEAN</kbd>. + * </li> + * <li> + * other (including strings and numeric strings) -> + * the data with single quotes escaped by preceeding + * single quotes, backslashes are escaped by preceeding + * backslashes, then the whole string is encapsulated + * between single quotes + * </li> + * </ul> + * + * @see DB_common::escapeSimple() + * @since Method available since Release 1.6.0 + */ + function quoteSmart($in) + { + if (is_int($in) || is_double($in)) { + return $in; + } elseif (is_bool($in)) { + return $in ? 1 : 0; + } elseif (is_null($in)) { + return 'NULL'; + } else { + return "'" . $this->escapeSimple($in) . "'"; + } + } + + // }}} + // {{{ escapeSimple() + + /** + * Escapes a string according to the current DBMS's standards + * + * In SQLite, this makes things safe for inserts/updates, but may + * cause problems when performing text comparisons against columns + * containing binary data. See the + * {@link http://php.net/sqlite_escape_string PHP manual} for more info. + * + * @param string $str the string to be escaped + * + * @return string the escaped string + * + * @see DB_common::quoteSmart() + * @since Method available since Release 1.6.0 + */ + function escapeSimple($str) + { + return str_replace("'", "''", $str); + } + + // }}} + // {{{ provides() + + /** + * Tells whether the present driver supports a given feature + * + * @param string $feature the feature you're curious about + * + * @return bool whether this driver supports $feature + */ + function provides($feature) + { + return $this->features[$feature]; + } + + // }}} + // {{{ setFetchMode() + + /** + * Sets the fetch mode that should be used by default for query results + * + * @param integer $fetchmode DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC + * or DB_FETCHMODE_OBJECT + * @param string $object_class the class name of the object to be returned + * by the fetch methods when the + * DB_FETCHMODE_OBJECT mode is selected. + * If no class is specified by default a cast + * to object from the assoc array row will be + * done. There is also the posibility to use + * and extend the 'DB_row' class. + * + * @see DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC, DB_FETCHMODE_OBJECT + */ + function setFetchMode($fetchmode, $object_class = 'stdClass') + { + switch ($fetchmode) { + case DB_FETCHMODE_OBJECT: + $this->fetchmode_object_class = $object_class; + case DB_FETCHMODE_ORDERED: + case DB_FETCHMODE_ASSOC: + $this->fetchmode = $fetchmode; + break; + default: + return $this->raiseError('invalid fetchmode mode'); + } + } + + // }}} + // {{{ setOption() + + /** + * Sets run-time configuration options for PEAR DB + * + * Options, their data types, default values and description: + * <ul> + * <li> + * <var>autofree</var> <kbd>boolean</kbd> = <samp>false</samp> + * <br />should results be freed automatically when there are no + * more rows? + * </li><li> + * <var>result_buffering</var> <kbd>integer</kbd> = <samp>500</samp> + * <br />how many rows of the result set should be buffered? + * <br />In mysql: mysql_unbuffered_query() is used instead of + * mysql_query() if this value is 0. (Release 1.7.0) + * <br />In oci8: this value is passed to ocisetprefetch(). + * (Release 1.7.0) + * </li><li> + * <var>debug</var> <kbd>integer</kbd> = <samp>0</samp> + * <br />debug level + * </li><li> + * <var>persistent</var> <kbd>boolean</kbd> = <samp>false</samp> + * <br />should the connection be persistent? + * </li><li> + * <var>portability</var> <kbd>integer</kbd> = <samp>DB_PORTABILITY_NONE</samp> + * <br />portability mode constant (see below) + * </li><li> + * <var>seqname_format</var> <kbd>string</kbd> = <samp>%s_seq</samp> + * <br />the sprintf() format string used on sequence names. This + * format is applied to sequence names passed to + * createSequence(), nextID() and dropSequence(). + * </li><li> + * <var>ssl</var> <kbd>boolean</kbd> = <samp>false</samp> + * <br />use ssl to connect? + * </li> + * </ul> + * + * ----------------------------------------- + * + * PORTABILITY MODES + * + * These modes are bitwised, so they can be combined using <kbd>|</kbd> + * and removed using <kbd>^</kbd>. See the examples section below on how + * to do this. + * + * <samp>DB_PORTABILITY_NONE</samp> + * turn off all portability features + * + * This mode gets automatically turned on if the deprecated + * <var>optimize</var> option gets set to <samp>performance</samp>. + * + * + * <samp>DB_PORTABILITY_LOWERCASE</samp> + * convert names of tables and fields to lower case when using + * <kbd>get*()</kbd>, <kbd>fetch*()</kbd> and <kbd>tableInfo()</kbd> + * + * This mode gets automatically turned on in the following databases + * if the deprecated option <var>optimize</var> gets set to + * <samp>portability</samp>: + * + oci8 + * + * + * <samp>DB_PORTABILITY_RTRIM</samp> + * right trim the data output by <kbd>get*()</kbd> <kbd>fetch*()</kbd> + * + * + * <samp>DB_PORTABILITY_DELETE_COUNT</samp> + * force reporting the number of rows deleted + * + * Some DBMS's don't count the number of rows deleted when performing + * simple <kbd>DELETE FROM tablename</kbd> queries. This portability + * mode tricks such DBMS's into telling the count by adding + * <samp>WHERE 1=1</samp> to the end of <kbd>DELETE</kbd> queries. + * + * This mode gets automatically turned on in the following databases + * if the deprecated option <var>optimize</var> gets set to + * <samp>portability</samp>: + * + fbsql + * + mysql + * + mysqli + * + sqlite + * + * + * <samp>DB_PORTABILITY_NUMROWS</samp> + * enable hack that makes <kbd>numRows()</kbd> work in Oracle + * + * This mode gets automatically turned on in the following databases + * if the deprecated option <var>optimize</var> gets set to + * <samp>portability</samp>: + * + oci8 + * + * + * <samp>DB_PORTABILITY_ERRORS</samp> + * makes certain error messages in certain drivers compatible + * with those from other DBMS's + * + * + mysql, mysqli: change unique/primary key constraints + * DB_ERROR_ALREADY_EXISTS -> DB_ERROR_CONSTRAINT + * + * + odbc(access): MS's ODBC driver reports 'no such field' as code + * 07001, which means 'too few parameters.' When this option is on + * that code gets mapped to DB_ERROR_NOSUCHFIELD. + * DB_ERROR_MISMATCH -> DB_ERROR_NOSUCHFIELD + * + * <samp>DB_PORTABILITY_NULL_TO_EMPTY</samp> + * convert null values to empty strings in data output by get*() and + * fetch*(). Needed because Oracle considers empty strings to be null, + * while most other DBMS's know the difference between empty and null. + * + * + * <samp>DB_PORTABILITY_ALL</samp> + * turn on all portability features + * + * ----------------------------------------- + * + * Example 1. Simple setOption() example + * <code> + * $db->setOption('autofree', true); + * </code> + * + * Example 2. Portability for lowercasing and trimming + * <code> + * $db->setOption('portability', + * DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_RTRIM); + * </code> + * + * Example 3. All portability options except trimming + * <code> + * $db->setOption('portability', + * DB_PORTABILITY_ALL ^ DB_PORTABILITY_RTRIM); + * </code> + * + * @param string $option option name + * @param mixed $value value for the option + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::$options + */ + function setOption($option, $value) + { + if (isset($this->options[$option])) { + $this->options[$option] = $value; + + /* + * Backwards compatibility check for the deprecated 'optimize' + * option. Done here in case settings change after connecting. + */ + if ($option == 'optimize') { + if ($value == 'portability') { + switch ($this->phptype) { + case 'oci8': + $this->options['portability'] = + DB_PORTABILITY_LOWERCASE | + DB_PORTABILITY_NUMROWS; + break; + case 'fbsql': + case 'mysql': + case 'mysqli': + case 'sqlite': + $this->options['portability'] = + DB_PORTABILITY_DELETE_COUNT; + break; + } + } else { + $this->options['portability'] = DB_PORTABILITY_NONE; + } + } + + return DB_OK; + } + return $this->raiseError("unknown option $option"); + } + + // }}} + // {{{ getOption() + + /** + * Returns the value of an option + * + * @param string $option the option name you're curious about + * + * @return mixed the option's value + */ + function getOption($option) + { + if (isset($this->options[$option])) { + return $this->options[$option]; + } + return $this->raiseError("unknown option $option"); + } + + // }}} + // {{{ prepare() + + /** + * Prepares a query for multiple execution with execute() + * + * Creates a query that can be run multiple times. Each time it is run, + * the placeholders, if any, will be replaced by the contents of + * execute()'s $data argument. + * + * Three types of placeholders can be used: + * + <kbd>?</kbd> scalar value (i.e. strings, integers). The system + * will automatically quote and escape the data. + * + <kbd>!</kbd> value is inserted 'as is' + * + <kbd>&</kbd> requires a file name. The file's contents get + * inserted into the query (i.e. saving binary + * data in a db) + * + * Example 1. + * <code> + * $sth = $db->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)'); + * $data = array( + * "John's text", + * "'it''s good'", + * 'filename.txt' + * ); + * $res = $db->execute($sth, $data); + * </code> + * + * Use backslashes to escape placeholder characters if you don't want + * them to be interpreted as placeholders: + * <pre> + * "UPDATE foo SET col=? WHERE col='over \& under'" + * </pre> + * + * With some database backends, this is emulated. + * + * {@internal ibase and oci8 have their own prepare() methods.}} + * + * @param string $query the query to be prepared + * + * @return mixed DB statement resource on success. A DB_Error object + * on failure. + * + * @see DB_common::execute() + */ + function prepare($query) + { + $tokens = preg_split('/((?<!\\\)[&?!])/', $query, -1, + PREG_SPLIT_DELIM_CAPTURE); + $token = 0; + $types = array(); + $newtokens = array(); + + foreach ($tokens as $val) { + switch ($val) { + case '?': + $types[$token++] = DB_PARAM_SCALAR; + break; + case '&': + $types[$token++] = DB_PARAM_OPAQUE; + break; + case '!': + $types[$token++] = DB_PARAM_MISC; + break; + default: + $newtokens[] = preg_replace('/\\\([&?!])/', "\\1", $val); + } + } + + $this->prepare_tokens[] = &$newtokens; + end($this->prepare_tokens); + + $k = key($this->prepare_tokens); + $this->prepare_types[$k] = $types; + $this->prepared_queries[$k] = implode(' ', $newtokens); + + return $k; + } + + // }}} + // {{{ autoPrepare() + + /** + * Automaticaly generates an insert or update query and pass it to prepare() + * + * @param string $table the table name + * @param array $table_fields the array of field names + * @param int $mode a type of query to make: + * DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE + * @param string $where for update queries: the WHERE clause to + * append to the SQL statement. Don't + * include the "WHERE" keyword. + * + * @return resource the query handle + * + * @uses DB_common::prepare(), DB_common::buildManipSQL() + */ + function autoPrepare($table, $table_fields, $mode = DB_AUTOQUERY_INSERT, + $where = false) + { + $query = $this->buildManipSQL($table, $table_fields, $mode, $where); + if (DB::isError($query)) { + return $query; + } + return $this->prepare($query); + } + + // }}} + // {{{ autoExecute() + + /** + * Automaticaly generates an insert or update query and call prepare() + * and execute() with it + * + * @param string $table the table name + * @param array $fields_values the associative array where $key is a + * field name and $value its value + * @param int $mode a type of query to make: + * DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE + * @param string $where for update queries: the WHERE clause to + * append to the SQL statement. Don't + * include the "WHERE" keyword. + * + * @return mixed a new DB_result object for successful SELECT queries + * or DB_OK for successul data manipulation queries. + * A DB_Error object on failure. + * + * @uses DB_common::autoPrepare(), DB_common::execute() + */ + function autoExecute($table, $fields_values, $mode = DB_AUTOQUERY_INSERT, + $where = false) + { + $sth = $this->autoPrepare($table, array_keys($fields_values), $mode, + $where); + if (DB::isError($sth)) { + return $sth; + } + $ret =& $this->execute($sth, array_values($fields_values)); + $this->freePrepared($sth); + return $ret; + + } + + // }}} + // {{{ buildManipSQL() + + /** + * Produces an SQL query string for autoPrepare() + * + * Example: + * <pre> + * buildManipSQL('table_sql', array('field1', 'field2', 'field3'), + * DB_AUTOQUERY_INSERT); + * </pre> + * + * That returns + * <samp> + * INSERT INTO table_sql (field1,field2,field3) VALUES (?,?,?) + * </samp> + * + * NOTES: + * - This belongs more to a SQL Builder class, but this is a simple + * facility. + * - Be carefull! If you don't give a $where param with an UPDATE + * query, all the records of the table will be updated! + * + * @param string $table the table name + * @param array $table_fields the array of field names + * @param int $mode a type of query to make: + * DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE + * @param string $where for update queries: the WHERE clause to + * append to the SQL statement. Don't + * include the "WHERE" keyword. + * + * @return string the sql query for autoPrepare() + */ + function buildManipSQL($table, $table_fields, $mode, $where = false) + { + if (count($table_fields) == 0) { + return $this->raiseError(DB_ERROR_NEED_MORE_DATA); + } + $first = true; + switch ($mode) { + case DB_AUTOQUERY_INSERT: + $values = ''; + $names = ''; + foreach ($table_fields as $value) { + if ($first) { + $first = false; + } else { + $names .= ','; + $values .= ','; + } + $names .= $value; + $values .= '?'; + } + return "INSERT INTO $table ($names) VALUES ($values)"; + case DB_AUTOQUERY_UPDATE: + $set = ''; + foreach ($table_fields as $value) { + if ($first) { + $first = false; + } else { + $set .= ','; + } + $set .= "$value = ?"; + } + $sql = "UPDATE $table SET $set"; + if ($where) { + $sql .= " WHERE $where"; + } + return $sql; + default: + return $this->raiseError(DB_ERROR_SYNTAX); + } + } + + // }}} + // {{{ execute() + + /** + * Executes a DB statement prepared with prepare() + * + * Example 1. + * <code> + * $sth = $db->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)'); + * $data = array( + * "John's text", + * "'it''s good'", + * 'filename.txt' + * ); + * $res =& $db->execute($sth, $data); + * </code> + * + * @param resource $stmt a DB statement resource returned from prepare() + * @param mixed $data array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return mixed a new DB_result object for successful SELECT queries + * or DB_OK for successul data manipulation queries. + * A DB_Error object on failure. + * + * {@internal ibase and oci8 have their own execute() methods.}} + * + * @see DB_common::prepare() + */ + function &execute($stmt, $data = array()) + { + $realquery = $this->executeEmulateQuery($stmt, $data); + if (DB::isError($realquery)) { + return $realquery; + } + $result = $this->simpleQuery($realquery); + + if ($result === DB_OK || DB::isError($result)) { + return $result; + } else { + $tmp =& new DB_result($this, $result); + return $tmp; + } + } + + // }}} + // {{{ executeEmulateQuery() + + /** + * Emulates executing prepared statements if the DBMS not support them + * + * @param resource $stmt a DB statement resource returned from execute() + * @param mixed $data array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return mixed a string containing the real query run when emulating + * prepare/execute. A DB_Error object on failure. + * + * @access protected + * @see DB_common::execute() + */ + function executeEmulateQuery($stmt, $data = array()) + { + $stmt = (int)$stmt; + $data = (array)$data; + $this->last_parameters = $data; + + if (count($this->prepare_types[$stmt]) != count($data)) { + $this->last_query = $this->prepared_queries[$stmt]; + return $this->raiseError(DB_ERROR_MISMATCH); + } + + $realquery = $this->prepare_tokens[$stmt][0]; + + $i = 0; + foreach ($data as $value) { + if ($this->prepare_types[$stmt][$i] == DB_PARAM_SCALAR) { + $realquery .= $this->quoteSmart($value); + } elseif ($this->prepare_types[$stmt][$i] == DB_PARAM_OPAQUE) { + $fp = @fopen($value, 'rb'); + if (!$fp) { + return $this->raiseError(DB_ERROR_ACCESS_VIOLATION); + } + $realquery .= $this->quoteSmart(fread($fp, filesize($value))); + fclose($fp); + } else { + $realquery .= $value; + } + + $realquery .= $this->prepare_tokens[$stmt][++$i]; + } + + return $realquery; + } + + // }}} + // {{{ executeMultiple() + + /** + * Performs several execute() calls on the same statement handle + * + * $data must be an array indexed numerically + * from 0, one execute call is done for every "row" in the array. + * + * If an error occurs during execute(), executeMultiple() does not + * execute the unfinished rows, but rather returns that error. + * + * @param resource $stmt query handle from prepare() + * @param array $data numeric array containing the + * data to insert into the query + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::prepare(), DB_common::execute() + */ + function executeMultiple($stmt, $data) + { + foreach ($data as $value) { + $res =& $this->execute($stmt, $value); + if (DB::isError($res)) { + return $res; + } + } + return DB_OK; + } + + // }}} + // {{{ freePrepared() + + /** + * Frees the internal resources associated with a prepared query + * + * @param resource $stmt the prepared statement's PHP resource + * @param bool $free_resource should the PHP resource be freed too? + * Use false if you need to get data + * from the result set later. + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_common::prepare() + */ + function freePrepared($stmt, $free_resource = true) + { + $stmt = (int)$stmt; + if (isset($this->prepare_tokens[$stmt])) { + unset($this->prepare_tokens[$stmt]); + unset($this->prepare_types[$stmt]); + unset($this->prepared_queries[$stmt]); + return true; + } + return false; + } + + // }}} + // {{{ modifyQuery() + + /** + * Changes a query string for various DBMS specific reasons + * + * It is defined here to ensure all drivers have this method available. + * + * @param string $query the query string to modify + * + * @return string the modified query string + * + * @access protected + * @see DB_mysql::modifyQuery(), DB_oci8::modifyQuery(), + * DB_sqlite::modifyQuery() + */ + function modifyQuery($query) + { + return $query; + } + + // }}} + // {{{ modifyLimitQuery() + + /** + * Adds LIMIT clauses to a query string according to current DBMS standards + * + * It is defined here to assure that all implementations + * have this method defined. + * + * @param string $query the query to modify + * @param int $from the row to start to fetching (0 = the first row) + * @param int $count the numbers of rows to fetch + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return string the query string with LIMIT clauses added + * + * @access protected + */ + function modifyLimitQuery($query, $from, $count, $params = array()) + { + return $query; + } + + // }}} + // {{{ query() + + /** + * Sends a query to the database server + * + * The query string can be either a normal statement to be sent directly + * to the server OR if <var>$params</var> are passed the query can have + * placeholders and it will be passed through prepare() and execute(). + * + * @param string $query the SQL query or the statement to prepare + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return mixed a new DB_result object for successful SELECT queries + * or DB_OK for successul data manipulation queries. + * A DB_Error object on failure. + * + * @see DB_result, DB_common::prepare(), DB_common::execute() + */ + function &query($query, $params = array()) + { + if (sizeof($params) > 0) { + $sth = $this->prepare($query); + if (DB::isError($sth)) { + return $sth; + } + $ret =& $this->execute($sth, $params); + $this->freePrepared($sth, false); + return $ret; + } else { + $this->last_parameters = array(); + $result = $this->simpleQuery($query); + if ($result === DB_OK || DB::isError($result)) { + return $result; + } else { + $tmp =& new DB_result($this, $result); + return $tmp; + } + } + } + + // }}} + // {{{ limitQuery() + + /** + * Generates and executes a LIMIT query + * + * @param string $query the query + * @param intr $from the row to start to fetching (0 = the first row) + * @param int $count the numbers of rows to fetch + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return mixed a new DB_result object for successful SELECT queries + * or DB_OK for successul data manipulation queries. + * A DB_Error object on failure. + */ + function &limitQuery($query, $from, $count, $params = array()) + { + $query = $this->modifyLimitQuery($query, $from, $count, $params); + if (DB::isError($query)){ + return $query; + } + $result =& $this->query($query, $params); + if (is_a($result, 'DB_result')) { + $result->setOption('limit_from', $from); + $result->setOption('limit_count', $count); + } + return $result; + } + + // }}} + // {{{ getOne() + + /** + * Fetches the first column of the first row from a query result + * + * Takes care of doing the query and freeing the results when finished. + * + * @param string $query the SQL query + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return mixed the returned value of the query. + * A DB_Error object on failure. + */ + function &getOne($query, $params = array()) + { + $params = (array)$params; + // modifyLimitQuery() would be nice here, but it causes BC issues + if (sizeof($params) > 0) { + $sth = $this->prepare($query); + if (DB::isError($sth)) { + return $sth; + } + $res =& $this->execute($sth, $params); + $this->freePrepared($sth); + } else { + $res =& $this->query($query); + } + + if (DB::isError($res)) { + return $res; + } + + $err = $res->fetchInto($row, DB_FETCHMODE_ORDERED); + $res->free(); + + if ($err !== DB_OK) { + return $err; + } + + return $row[0]; + } + + // }}} + // {{{ getRow() + + /** + * Fetches the first row of data returned from a query result + * + * Takes care of doing the query and freeing the results when finished. + * + * @param string $query the SQL query + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * @param int $fetchmode the fetch mode to use + * + * @return array the first row of results as an array. + * A DB_Error object on failure. + */ + function &getRow($query, $params = array(), + $fetchmode = DB_FETCHMODE_DEFAULT) + { + // compat check, the params and fetchmode parameters used to + // have the opposite order + if (!is_array($params)) { + if (is_array($fetchmode)) { + if ($params === null) { + $tmp = DB_FETCHMODE_DEFAULT; + } else { + $tmp = $params; + } + $params = $fetchmode; + $fetchmode = $tmp; + } elseif ($params !== null) { + $fetchmode = $params; + $params = array(); + } + } + // modifyLimitQuery() would be nice here, but it causes BC issues + if (sizeof($params) > 0) { + $sth = $this->prepare($query); + if (DB::isError($sth)) { + return $sth; + } + $res =& $this->execute($sth, $params); + $this->freePrepared($sth); + } else { + $res =& $this->query($query); + } + + if (DB::isError($res)) { + return $res; + } + + $err = $res->fetchInto($row, $fetchmode); + + $res->free(); + + if ($err !== DB_OK) { + return $err; + } + + return $row; + } + + // }}} + // {{{ getCol() + + /** + * Fetches a single column from a query result and returns it as an + * indexed array + * + * @param string $query the SQL query + * @param mixed $col which column to return (integer [column number, + * starting at 0] or string [column name]) + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return array the results as an array. A DB_Error object on failure. + * + * @see DB_common::query() + */ + function &getCol($query, $col = 0, $params = array()) + { + $params = (array)$params; + if (sizeof($params) > 0) { + $sth = $this->prepare($query); + + if (DB::isError($sth)) { + return $sth; + } + + $res =& $this->execute($sth, $params); + $this->freePrepared($sth); + } else { + $res =& $this->query($query); + } + + if (DB::isError($res)) { + return $res; + } + + $fetchmode = is_int($col) ? DB_FETCHMODE_ORDERED : DB_FETCHMODE_ASSOC; + + if (!is_array($row = $res->fetchRow($fetchmode))) { + $ret = array(); + } else { + if (!array_key_exists($col, $row)) { + $ret =& $this->raiseError(DB_ERROR_NOSUCHFIELD); + } else { + $ret = array($row[$col]); + while (is_array($row = $res->fetchRow($fetchmode))) { + $ret[] = $row[$col]; + } + } + } + + $res->free(); + + if (DB::isError($row)) { + $ret = $row; + } + + return $ret; + } + + // }}} + // {{{ getAssoc() + + /** + * Fetches an entire query result and returns it as an + * associative array using the first column as the key + * + * If the result set contains more than two columns, the value + * will be an array of the values from column 2-n. If the result + * set contains only two columns, the returned value will be a + * scalar with the value of the second column (unless forced to an + * array with the $force_array parameter). A DB error code is + * returned on errors. If the result set contains fewer than two + * columns, a DB_ERROR_TRUNCATED error is returned. + * + * For example, if the table "mytable" contains: + * + * <pre> + * ID TEXT DATE + * -------------------------------- + * 1 'one' 944679408 + * 2 'two' 944679408 + * 3 'three' 944679408 + * </pre> + * + * Then the call getAssoc('SELECT id,text FROM mytable') returns: + * <pre> + * array( + * '1' => 'one', + * '2' => 'two', + * '3' => 'three', + * ) + * </pre> + * + * ...while the call getAssoc('SELECT id,text,date FROM mytable') returns: + * <pre> + * array( + * '1' => array('one', '944679408'), + * '2' => array('two', '944679408'), + * '3' => array('three', '944679408') + * ) + * </pre> + * + * If the more than one row occurs with the same value in the + * first column, the last row overwrites all previous ones by + * default. Use the $group parameter if you don't want to + * overwrite like this. Example: + * + * <pre> + * getAssoc('SELECT category,id,name FROM mytable', false, null, + * DB_FETCHMODE_ASSOC, true) returns: + * + * array( + * '1' => array(array('id' => '4', 'name' => 'number four'), + * array('id' => '6', 'name' => 'number six') + * ), + * '9' => array(array('id' => '4', 'name' => 'number four'), + * array('id' => '6', 'name' => 'number six') + * ) + * ) + * </pre> + * + * Keep in mind that database functions in PHP usually return string + * values for results regardless of the database's internal type. + * + * @param string $query the SQL query + * @param bool $force_array used only when the query returns + * exactly two columns. If true, the values + * of the returned array will be one-element + * arrays instead of scalars. + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of + * items passed must match quantity of + * placeholders in query: meaning 1 + * placeholder for non-array parameters or + * 1 placeholder per array element. + * @param int $fetchmode the fetch mode to use + * @param bool $group if true, the values of the returned array + * is wrapped in another array. If the same + * key value (in the first column) repeats + * itself, the values will be appended to + * this array instead of overwriting the + * existing values. + * + * @return array the associative array containing the query results. + * A DB_Error object on failure. + */ + function &getAssoc($query, $force_array = false, $params = array(), + $fetchmode = DB_FETCHMODE_DEFAULT, $group = false) + { + $params = (array)$params; + if (sizeof($params) > 0) { + $sth = $this->prepare($query); + + if (DB::isError($sth)) { + return $sth; + } + + $res =& $this->execute($sth, $params); + $this->freePrepared($sth); + } else { + $res =& $this->query($query); + } + + if (DB::isError($res)) { + return $res; + } + if ($fetchmode == DB_FETCHMODE_DEFAULT) { + $fetchmode = $this->fetchmode; + } + $cols = $res->numCols(); + + if ($cols < 2) { + $tmp =& $this->raiseError(DB_ERROR_TRUNCATED); + return $tmp; + } + + $results = array(); + + if ($cols > 2 || $force_array) { + // return array values + // XXX this part can be optimized + if ($fetchmode == DB_FETCHMODE_ASSOC) { + while (is_array($row = $res->fetchRow(DB_FETCHMODE_ASSOC))) { + reset($row); + $key = current($row); + unset($row[key($row)]); + if ($group) { + $results[$key][] = $row; + } else { + $results[$key] = $row; + } + } + } elseif ($fetchmode == DB_FETCHMODE_OBJECT) { + while ($row = $res->fetchRow(DB_FETCHMODE_OBJECT)) { + $arr = get_object_vars($row); + $key = current($arr); + if ($group) { + $results[$key][] = $row; + } else { + $results[$key] = $row; + } + } + } else { + while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) { + // we shift away the first element to get + // indices running from 0 again + $key = array_shift($row); + if ($group) { + $results[$key][] = $row; + } else { + $results[$key] = $row; + } + } + } + if (DB::isError($row)) { + $results = $row; + } + } else { + // return scalar values + while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) { + if ($group) { + $results[$row[0]][] = $row[1]; + } else { + $results[$row[0]] = $row[1]; + } + } + if (DB::isError($row)) { + $results = $row; + } + } + + $res->free(); + + return $results; + } + + // }}} + // {{{ getAll() + + /** + * Fetches all of the rows from a query result + * + * @param string $query the SQL query + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of + * items passed must match quantity of + * placeholders in query: meaning 1 + * placeholder for non-array parameters or + * 1 placeholder per array element. + * @param int $fetchmode the fetch mode to use: + * + DB_FETCHMODE_ORDERED + * + DB_FETCHMODE_ASSOC + * + DB_FETCHMODE_ORDERED | DB_FETCHMODE_FLIPPED + * + DB_FETCHMODE_ASSOC | DB_FETCHMODE_FLIPPED + * + * @return array the nested array. A DB_Error object on failure. + */ + function &getAll($query, $params = array(), + $fetchmode = DB_FETCHMODE_DEFAULT) + { + // compat check, the params and fetchmode parameters used to + // have the opposite order + if (!is_array($params)) { + if (is_array($fetchmode)) { + if ($params === null) { + $tmp = DB_FETCHMODE_DEFAULT; + } else { + $tmp = $params; + } + $params = $fetchmode; + $fetchmode = $tmp; + } elseif ($params !== null) { + $fetchmode = $params; + $params = array(); + } + } + + if (sizeof($params) > 0) { + $sth = $this->prepare($query); + + if (DB::isError($sth)) { + return $sth; + } + + $res =& $this->execute($sth, $params); + $this->freePrepared($sth); + } else { + $res =& $this->query($query); + } + + if ($res === DB_OK || DB::isError($res)) { + return $res; + } + + $results = array(); + while (DB_OK === $res->fetchInto($row, $fetchmode)) { + if ($fetchmode & DB_FETCHMODE_FLIPPED) { + foreach ($row as $key => $val) { + $results[$key][] = $val; + } + } else { + $results[] = $row; + } + } + + $res->free(); + + if (DB::isError($row)) { + $tmp =& $this->raiseError($row); + return $tmp; + } + return $results; + } + + // }}} + // {{{ autoCommit() + + /** + * Enables or disables automatic commits + * + * @param bool $onoff true turns it on, false turns it off + * + * @return int DB_OK on success. A DB_Error object if the driver + * doesn't support auto-committing transactions. + */ + function autoCommit($onoff = false) + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ commit() + + /** + * Commits the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function commit() + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ rollback() + + /** + * Reverts the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function rollback() + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ numRows() + + /** + * Determines the number of rows in a query result + * + * @param resource $result the query result idenifier produced by PHP + * + * @return int the number of rows. A DB_Error object on failure. + */ + function numRows($result) + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ affectedRows() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ getSequenceName() + + /** + * Generates the name used inside the database for a sequence + * + * The createSequence() docblock contains notes about storing sequence + * names. + * + * @param string $sqn the sequence's public name + * + * @return string the sequence's name in the backend + * + * @access protected + * @see DB_common::createSequence(), DB_common::dropSequence(), + * DB_common::nextID(), DB_common::setOption() + */ + function getSequenceName($sqn) + { + return sprintf($this->getOption('seqname_format'), + preg_replace('/[^a-z0-9_.]/i', '_', $sqn)); + } + + // }}} + // {{{ nextId() + + /** + * Returns the next free id in a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true, the seqence is automatically + * created if it does not exist + * + * @return int the next id number in the sequence. + * A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::dropSequence(), + * DB_common::getSequenceName() + */ + function nextId($seq_name, $ondemand = true) + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ createSequence() + + /** + * Creates a new sequence + * + * The name of a given sequence is determined by passing the string + * provided in the <var>$seq_name</var> argument through PHP's sprintf() + * function using the value from the <var>seqname_format</var> option as + * the sprintf()'s format argument. + * + * <var>seqname_format</var> is set via setOption(). + * + * @param string $seq_name name of the new sequence + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::dropSequence(), DB_common::getSequenceName(), + * DB_common::nextID() + */ + function createSequence($seq_name) + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ dropSequence() + + /** + * Deletes a sequence + * + * @param string $seq_name name of the sequence to be deleted + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::getSequenceName(), + * DB_common::nextID() + */ + function dropSequence($seq_name) + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ raiseError() + + /** + * Communicates an error and invoke error callbacks, etc + * + * Basically a wrapper for PEAR::raiseError without the message string. + * + * @param mixed integer error code, or a PEAR error object (all + * other parameters are ignored if this parameter is + * an object + * @param int error mode, see PEAR_Error docs + * @param mixed if error mode is PEAR_ERROR_TRIGGER, this is the + * error level (E_USER_NOTICE etc). If error mode is + * PEAR_ERROR_CALLBACK, this is the callback function, + * either as a function name, or as an array of an + * object and method name. For other error modes this + * parameter is ignored. + * @param string extra debug information. Defaults to the last + * query and native error code. + * @param mixed native error code, integer or string depending the + * backend + * + * @return object the PEAR_Error object + * + * @see PEAR_Error + */ + function &raiseError($code = DB_ERROR, $mode = null, $options = null, + $userinfo = null, $nativecode = null) + { + // The error is yet a DB error object + if (is_object($code)) { + // because we the static PEAR::raiseError, our global + // handler should be used if it is set + if ($mode === null && !empty($this->_default_error_mode)) { + $mode = $this->_default_error_mode; + $options = $this->_default_error_options; + } + $tmp = PEAR::raiseError($code, null, $mode, $options, + null, null, true); + return $tmp; + } + + if ($userinfo === null) { + $userinfo = $this->last_query; + } + + if ($nativecode) { + $userinfo .= ' [nativecode=' . trim($nativecode) . ']'; + } else { + $userinfo .= ' [DB Error: ' . DB::errorMessage($code) . ']'; + } + + $tmp = PEAR::raiseError(null, $code, $mode, $options, $userinfo, + 'DB_Error', true); + return $tmp; + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error code produced by the last query + * + * @return mixed the DBMS' error code. A DB_Error object on failure. + */ + function errorNative() + { + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ errorCode() + + /** + * Maps native error codes to DB's portable ones + * + * Uses the <var>$errorcode_map</var> property defined in each driver. + * + * @param string|int $nativecode the error code returned by the DBMS + * + * @return int the portable DB error code. Return DB_ERROR if the + * current driver doesn't have a mapping for the + * $nativecode submitted. + */ + function errorCode($nativecode) + { + if (isset($this->errorcode_map[$nativecode])) { + return $this->errorcode_map[$nativecode]; + } + // Fall back to DB_ERROR if there was no mapping. + return DB_ERROR; + } + + // }}} + // {{{ errorMessage() + + /** + * Maps a DB error code to a textual message + * + * @param integer $dbcode the DB error code + * + * @return string the error message corresponding to the error code + * submitted. FALSE if the error code is unknown. + * + * @see DB::errorMessage() + */ + function errorMessage($dbcode) + { + return DB::errorMessage($this->errorcode_map[$dbcode]); + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * The format of the resulting array depends on which <var>$mode</var> + * you select. The sample output below is based on this query: + * <pre> + * SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId + * FROM tblFoo + * JOIN tblBar ON tblFoo.fldId = tblBar.fldId + * </pre> + * + * <ul> + * <li> + * + * <kbd>null</kbd> (default) + * <pre> + * [0] => Array ( + * [table] => tblFoo + * [name] => fldId + * [type] => int + * [len] => 11 + * [flags] => primary_key not_null + * ) + * [1] => Array ( + * [table] => tblFoo + * [name] => fldPhone + * [type] => string + * [len] => 20 + * [flags] => + * ) + * [2] => Array ( + * [table] => tblBar + * [name] => fldId + * [type] => int + * [len] => 11 + * [flags] => primary_key not_null + * ) + * </pre> + * + * </li><li> + * + * <kbd>DB_TABLEINFO_ORDER</kbd> + * + * <p>In addition to the information found in the default output, + * a notation of the number of columns is provided by the + * <samp>num_fields</samp> element while the <samp>order</samp> + * element provides an array with the column names as the keys and + * their location index number (corresponding to the keys in the + * the default output) as the values.</p> + * + * <p>If a result set has identical field names, the last one is + * used.</p> + * + * <pre> + * [num_fields] => 3 + * [order] => Array ( + * [fldId] => 2 + * [fldTrans] => 1 + * ) + * </pre> + * + * </li><li> + * + * <kbd>DB_TABLEINFO_ORDERTABLE</kbd> + * + * <p>Similar to <kbd>DB_TABLEINFO_ORDER</kbd> but adds more + * dimensions to the array in which the table names are keys and + * the field names are sub-keys. This is helpful for queries that + * join tables which have identical field names.</p> + * + * <pre> + * [num_fields] => 3 + * [ordertable] => Array ( + * [tblFoo] => Array ( + * [fldId] => 0 + * [fldPhone] => 1 + * ) + * [tblBar] => Array ( + * [fldId] => 2 + * ) + * ) + * </pre> + * + * </li> + * </ul> + * + * The <samp>flags</samp> element contains a space separated list + * of extra information about the field. This data is inconsistent + * between DBMS's due to the way each DBMS works. + * + <samp>primary_key</samp> + * + <samp>unique_key</samp> + * + <samp>multiple_key</samp> + * + <samp>not_null</samp> + * + * Most DBMS's only provide the <samp>table</samp> and <samp>flags</samp> + * elements if <var>$result</var> is a table name. The following DBMS's + * provide full information from queries: + * + fbsql + * + mysql + * + * If the 'portability' option has <samp>DB_PORTABILITY_LOWERCASE</samp> + * turned on, the names of tables and fields will be lowercased. + * + * @param object|string $result DB_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode either unused or one of the tableInfo modes: + * <kbd>DB_TABLEINFO_ORDERTABLE</kbd>, + * <kbd>DB_TABLEINFO_ORDER</kbd> or + * <kbd>DB_TABLEINFO_FULL</kbd> (which does both). + * These are bitwise, so the first two can be + * combined using <kbd>|</kbd>. + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::setOption() + */ + function tableInfo($result, $mode = null) + { + /* + * If the DB_<driver> class has a tableInfo() method, that one + * overrides this one. But, if the driver doesn't have one, + * this method runs and tells users about that fact. + */ + return $this->raiseError(DB_ERROR_NOT_CAPABLE); + } + + // }}} + // {{{ getTables() + + /** + * Lists the tables in the current database + * + * @return array the list of tables. A DB_Error object on failure. + * + * @deprecated Method deprecated some time before Release 1.2 + */ + function getTables() + { + return $this->getListOf('tables'); + } + + // }}} + // {{{ getListOf() + + /** + * Lists internal database information + * + * @param string $type type of information being sought. + * Common items being sought are: + * tables, databases, users, views, functions + * Each DBMS's has its own capabilities. + * + * @return array an array listing the items sought. + * A DB DB_Error object on failure. + */ + function getListOf($type) + { + $sql = $this->getSpecialQuery($type); + if ($sql === null) { + $this->last_query = ''; + return $this->raiseError(DB_ERROR_UNSUPPORTED); + } elseif (is_int($sql) || DB::isError($sql)) { + // Previous error + return $this->raiseError($sql); + } elseif (is_array($sql)) { + // Already the result + return $sql; + } + // Launch this query + return $this->getCol($sql); + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtains the query string needed for listing a given type of objects + * + * @param string $type the kind of objects you want to retrieve + * + * @return string the SQL query string or null if the driver doesn't + * support the object type requested + * + * @access protected + * @see DB_common::getListOf() + */ + function getSpecialQuery($type) + { + return $this->raiseError(DB_ERROR_UNSUPPORTED); + } + + // }}} + // {{{ _rtrimArrayValues() + + /** + * Right-trims all strings in an array + * + * @param array $array the array to be trimmed (passed by reference) + * + * @return void + * + * @access protected + */ + function _rtrimArrayValues(&$array) + { + foreach ($array as $key => $value) { + if (is_string($value)) { + $array[$key] = rtrim($value); + } + } + } + + // }}} + // {{{ _convertNullArrayValuesToEmpty() + + /** + * Converts all null values in an array to empty strings + * + * @param array $array the array to be de-nullified (passed by reference) + * + * @return void + * + * @access protected + */ + function _convertNullArrayValuesToEmpty(&$array) + { + foreach ($array as $key => $value) { + if (is_null($value)) { + $array[$key] = ''; + } + } + } + + // }}} +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/plugins/tidypics/lib/phpFlickr/PEAR/DB/mysql.php b/plugins/tidypics/lib/phpFlickr/PEAR/DB/mysql.php new file mode 100644 index 0000000000000000000000000000000000000000..3ae0adf86cddbfe7612daec8ff4b279fbaaa2202 --- /dev/null +++ b/plugins/tidypics/lib/phpFlickr/PEAR/DB/mysql.php @@ -0,0 +1,1034 @@ +<?php + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * The PEAR DB driver for PHP's mysql extension + * for interacting with MySQL databases + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category Database + * @package DB + * @author Stig Bakken <ssb@php.net> + * @author Daniel Convissor <danielc@php.net> + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: mysql.php 32 2005-08-01 06:21:02Z dancoulter $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB_common class so it can be extended from + */ +require_once 'DB/common.php'; + +/** + * The methods PEAR DB uses to interact with PHP's mysql extension + * for interacting with MySQL databases + * + * These methods overload the ones declared in DB_common. + * + * @category Database + * @package DB + * @author Stig Bakken <ssb@php.net> + * @author Daniel Convissor <danielc@php.net> + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_mysql extends DB_common +{ + // {{{ properties + + /** + * The DB driver type (mysql, oci8, odbc, etc.) + * @var string + */ + var $phptype = 'mysql'; + + /** + * The database syntax variant to be used (db2, access, etc.), if any + * @var string + */ + var $dbsyntax = 'mysql'; + + /** + * The capabilities of this DB implementation + * + * The 'new_link' element contains the PHP version that first provided + * new_link support for this DBMS. Contains false if it's unsupported. + * + * Meaning of the 'limit' element: + * + 'emulate' = emulate with fetch row by number + * + 'alter' = alter the query + * + false = skip rows + * + * @var array + */ + var $features = array( + 'limit' => 'alter', + 'new_link' => '4.2.0', + 'numrows' => true, + 'pconnect' => true, + 'prepare' => false, + 'ssl' => false, + 'transactions' => true, + ); + + /** + * A mapping of native error codes to DB error codes + * @var array + */ + var $errorcode_map = array( + 1004 => DB_ERROR_CANNOT_CREATE, + 1005 => DB_ERROR_CANNOT_CREATE, + 1006 => DB_ERROR_CANNOT_CREATE, + 1007 => DB_ERROR_ALREADY_EXISTS, + 1008 => DB_ERROR_CANNOT_DROP, + 1022 => DB_ERROR_ALREADY_EXISTS, + 1044 => DB_ERROR_ACCESS_VIOLATION, + 1046 => DB_ERROR_NODBSELECTED, + 1048 => DB_ERROR_CONSTRAINT, + 1049 => DB_ERROR_NOSUCHDB, + 1050 => DB_ERROR_ALREADY_EXISTS, + 1051 => DB_ERROR_NOSUCHTABLE, + 1054 => DB_ERROR_NOSUCHFIELD, + 1061 => DB_ERROR_ALREADY_EXISTS, + 1062 => DB_ERROR_ALREADY_EXISTS, + 1064 => DB_ERROR_SYNTAX, + 1091 => DB_ERROR_NOT_FOUND, + 1100 => DB_ERROR_NOT_LOCKED, + 1136 => DB_ERROR_VALUE_COUNT_ON_ROW, + 1142 => DB_ERROR_ACCESS_VIOLATION, + 1146 => DB_ERROR_NOSUCHTABLE, + 1216 => DB_ERROR_CONSTRAINT, + 1217 => DB_ERROR_CONSTRAINT, + ); + + /** + * The raw database connection created by PHP + * @var resource + */ + var $connection; + + /** + * The DSN information for connecting to a database + * @var array + */ + var $dsn = array(); + + + /** + * Should data manipulation queries be committed automatically? + * @var bool + * @access private + */ + var $autocommit = true; + + /** + * The quantity of transactions begun + * + * {@internal While this is private, it can't actually be designated + * private in PHP 5 because it is directly accessed in the test suite.}} + * + * @var integer + * @access private + */ + var $transaction_opcount = 0; + + /** + * The database specified in the DSN + * + * It's a fix to allow calls to different databases in the same script. + * + * @var string + * @access private + */ + var $_db = ''; + + + // }}} + // {{{ constructor + + /** + * This constructor calls <kbd>$this->DB_common()</kbd> + * + * @return void + */ + function DB_mysql() + { + $this->DB_common(); + } + + // }}} + // {{{ connect() + + /** + * Connect to the database server, log in and open the database + * + * Don't call this method directly. Use DB::connect() instead. + * + * PEAR DB's mysql driver supports the following extra DSN options: + * + new_link If set to true, causes subsequent calls to connect() + * to return a new connection link instead of the + * existing one. WARNING: this is not portable to + * other DBMS's. Available since PEAR DB 1.7.0. + * + client_flags Any combination of MYSQL_CLIENT_* constants. + * Only used if PHP is at version 4.3.0 or greater. + * Available since PEAR DB 1.7.0. + * + * @param array $dsn the data source name + * @param bool $persistent should the connection be persistent? + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function connect($dsn, $persistent = false) + { + if (!PEAR::loadExtension('mysql')) { + return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); + } + + $this->dsn = $dsn; + if ($dsn['dbsyntax']) { + $this->dbsyntax = $dsn['dbsyntax']; + } + + $params = array(); + if ($dsn['protocol'] && $dsn['protocol'] == 'unix') { + $params[0] = ':' . $dsn['socket']; + } else { + $params[0] = $dsn['hostspec'] ? $dsn['hostspec'] + : 'localhost'; + if ($dsn['port']) { + $params[0] .= ':' . $dsn['port']; + } + } + $params[] = $dsn['username'] ? $dsn['username'] : null; + $params[] = $dsn['password'] ? $dsn['password'] : null; + + if (!$persistent) { + if (isset($dsn['new_link']) + && ($dsn['new_link'] == 'true' || $dsn['new_link'] === true)) + { + $params[] = true; + } else { + $params[] = false; + } + } + if (version_compare(phpversion(), '4.3.0', '>=')) { + $params[] = isset($dsn['client_flags']) + ? $dsn['client_flags'] : null; + } + + $connect_function = $persistent ? 'mysql_pconnect' : 'mysql_connect'; + + $ini = ini_get('track_errors'); + $php_errormsg = ''; + if ($ini) { + $this->connection = @call_user_func_array($connect_function, + $params); + } else { + ini_set('track_errors', 1); + $this->connection = @call_user_func_array($connect_function, + $params); + ini_set('track_errors', $ini); + } + + if (!$this->connection) { + if (($err = @mysql_error()) != '') { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + $err); + } else { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + $php_errormsg); + } + } + + if ($dsn['database']) { + if (!@mysql_select_db($dsn['database'], $this->connection)) { + return $this->mysqlRaiseError(); + } + $this->_db = $dsn['database']; + } + + return DB_OK; + } + + // }}} + // {{{ disconnect() + + /** + * Disconnects from the database server + * + * @return bool TRUE on success, FALSE on failure + */ + function disconnect() + { + $ret = @mysql_close($this->connection); + $this->connection = null; + return $ret; + } + + // }}} + // {{{ simpleQuery() + + /** + * Sends a query to the database server + * + * Generally uses mysql_query(). If you want to use + * mysql_unbuffered_query() set the "result_buffering" option to 0 using + * setOptions(). This option was added in Release 1.7.0. + * + * @param string the SQL query string + * + * @return mixed + a PHP result resrouce for successful SELECT queries + * + the DB_OK constant for other successful queries + * + a DB_Error object on failure + */ + function simpleQuery($query) + { + $ismanip = DB::isManip($query); + $this->last_query = $query; + $query = $this->modifyQuery($query); + if ($this->_db) { + if (!@mysql_select_db($this->_db, $this->connection)) { + return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); + } + } + if (!$this->autocommit && $ismanip) { + if ($this->transaction_opcount == 0) { + $result = @mysql_query('SET AUTOCOMMIT=0', $this->connection); + $result = @mysql_query('BEGIN', $this->connection); + if (!$result) { + return $this->mysqlRaiseError(); + } + } + $this->transaction_opcount++; + } + if (!$this->options['result_buffering']) { + $result = @mysql_unbuffered_query($query, $this->connection); + } else { + $result = @mysql_query($query, $this->connection); + } + if (!$result) { + return $this->mysqlRaiseError(); + } + if (is_resource($result)) { + return $result; + } + return DB_OK; + } + + // }}} + // {{{ nextResult() + + /** + * Move the internal mysql result pointer to the next available result + * + * This method has not been implemented yet. + * + * @param a valid sql result resource + * + * @return false + */ + function nextResult($result) + { + return false; + } + + // }}} + // {{{ fetchInto() + + /** + * Places a row from the result set into the given array + * + * Formating of the array and the data therein are configurable. + * See DB_result::fetchInto() for more information. + * + * This method is not meant to be called directly. Use + * DB_result::fetchInto() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result the query result resource + * @param array $arr the referenced array to put the data in + * @param int $fetchmode how the resulting array should be indexed + * @param int $rownum the row number to fetch (0 = first row) + * + * @return mixed DB_OK on success, NULL when the end of a result set is + * reached or on failure + * + * @see DB_result::fetchInto() + */ + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + if ($rownum !== null) { + if (!@mysql_data_seek($result, $rownum)) { + return null; + } + } + if ($fetchmode & DB_FETCHMODE_ASSOC) { + $arr = @mysql_fetch_array($result, MYSQL_ASSOC); + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { + $arr = array_change_key_case($arr, CASE_LOWER); + } + } else { + $arr = @mysql_fetch_row($result); + } + if (!$arr) { + return null; + } + if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { + /* + * Even though this DBMS already trims output, we do this because + * a field might have intentional whitespace at the end that + * gets removed by DB_PORTABILITY_RTRIM under another driver. + */ + $this->_rtrimArrayValues($arr); + } + if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + return DB_OK; + } + + // }}} + // {{{ freeResult() + + /** + * Deletes the result set and frees the memory occupied by the result set + * + * This method is not meant to be called directly. Use + * DB_result::free() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_result::free() + */ + function freeResult($result) + { + return @mysql_free_result($result); + } + + // }}} + // {{{ numCols() + + /** + * Gets the number of columns in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numCols() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of columns. A DB_Error object on failure. + * + * @see DB_result::numCols() + */ + function numCols($result) + { + $cols = @mysql_num_fields($result); + if (!$cols) { + return $this->mysqlRaiseError(); + } + return $cols; + } + + // }}} + // {{{ numRows() + + /** + * Gets the number of rows in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numRows() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of rows. A DB_Error object on failure. + * + * @see DB_result::numRows() + */ + function numRows($result) + { + $rows = @mysql_num_rows($result); + if ($rows === null) { + return $this->mysqlRaiseError(); + } + return $rows; + } + + // }}} + // {{{ autoCommit() + + /** + * Enables or disables automatic commits + * + * @param bool $onoff true turns it on, false turns it off + * + * @return int DB_OK on success. A DB_Error object if the driver + * doesn't support auto-committing transactions. + */ + function autoCommit($onoff = false) + { + // XXX if $this->transaction_opcount > 0, we should probably + // issue a warning here. + $this->autocommit = $onoff ? true : false; + return DB_OK; + } + + // }}} + // {{{ commit() + + /** + * Commits the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function commit() + { + if ($this->transaction_opcount > 0) { + if ($this->_db) { + if (!@mysql_select_db($this->_db, $this->connection)) { + return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); + } + } + $result = @mysql_query('COMMIT', $this->connection); + $result = @mysql_query('SET AUTOCOMMIT=1', $this->connection); + $this->transaction_opcount = 0; + if (!$result) { + return $this->mysqlRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ rollback() + + /** + * Reverts the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function rollback() + { + if ($this->transaction_opcount > 0) { + if ($this->_db) { + if (!@mysql_select_db($this->_db, $this->connection)) { + return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); + } + } + $result = @mysql_query('ROLLBACK', $this->connection); + $result = @mysql_query('SET AUTOCOMMIT=1', $this->connection); + $this->transaction_opcount = 0; + if (!$result) { + return $this->mysqlRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ affectedRows() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + if (DB::isManip($this->last_query)) { + return @mysql_affected_rows($this->connection); + } else { + return 0; + } + } + + // }}} + // {{{ nextId() + + /** + * Returns the next free id in a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true, the seqence is automatically + * created if it does not exist + * + * @return int the next id number in the sequence. + * A DB_Error object on failure. + * + * @see DB_common::nextID(), DB_common::getSequenceName(), + * DB_mysql::createSequence(), DB_mysql::dropSequence() + */ + function nextId($seq_name, $ondemand = true) + { + $seqname = $this->getSequenceName($seq_name); + do { + $repeat = 0; + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result = $this->query("UPDATE ${seqname} ". + 'SET id=LAST_INSERT_ID(id+1)'); + $this->popErrorHandling(); + if ($result === DB_OK) { + // COMMON CASE + $id = @mysql_insert_id($this->connection); + if ($id != 0) { + return $id; + } + // EMPTY SEQ TABLE + // Sequence table must be empty for some reason, so fill + // it and return 1 and obtain a user-level lock + $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)"); + if (DB::isError($result)) { + return $this->raiseError($result); + } + if ($result == 0) { + // Failed to get the lock + return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED); + } + + // add the default value + $result = $this->query("REPLACE INTO ${seqname} (id) VALUES (0)"); + if (DB::isError($result)) { + return $this->raiseError($result); + } + + // Release the lock + $result = $this->getOne('SELECT RELEASE_LOCK(' + . "'${seqname}_lock')"); + if (DB::isError($result)) { + return $this->raiseError($result); + } + // We know what the result will be, so no need to try again + return 1; + + } elseif ($ondemand && DB::isError($result) && + $result->getCode() == DB_ERROR_NOSUCHTABLE) + { + // ONDEMAND TABLE CREATION + $result = $this->createSequence($seq_name); + if (DB::isError($result)) { + return $this->raiseError($result); + } else { + $repeat = 1; + } + + } elseif (DB::isError($result) && + $result->getCode() == DB_ERROR_ALREADY_EXISTS) + { + // BACKWARDS COMPAT + // see _BCsequence() comment + $result = $this->_BCsequence($seqname); + if (DB::isError($result)) { + return $this->raiseError($result); + } + $repeat = 1; + } + } while ($repeat); + + return $this->raiseError($result); + } + + // }}} + // {{{ createSequence() + + /** + * Creates a new sequence + * + * @param string $seq_name name of the new sequence + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::getSequenceName(), + * DB_mysql::nextID(), DB_mysql::dropSequence() + */ + function createSequence($seq_name) + { + $seqname = $this->getSequenceName($seq_name); + $res = $this->query('CREATE TABLE ' . $seqname + . ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,' + . ' PRIMARY KEY(id))'); + if (DB::isError($res)) { + return $res; + } + // insert yields value 1, nextId call will generate ID 2 + $res = $this->query("INSERT INTO ${seqname} (id) VALUES (0)"); + if (DB::isError($res)) { + return $res; + } + // so reset to zero + return $this->query("UPDATE ${seqname} SET id = 0"); + } + + // }}} + // {{{ dropSequence() + + /** + * Deletes a sequence + * + * @param string $seq_name name of the sequence to be deleted + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::dropSequence(), DB_common::getSequenceName(), + * DB_mysql::nextID(), DB_mysql::createSequence() + */ + function dropSequence($seq_name) + { + return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); + } + + // }}} + // {{{ _BCsequence() + + /** + * Backwards compatibility with old sequence emulation implementation + * (clean up the dupes) + * + * @param string $seqname the sequence name to clean up + * + * @return bool true on success. A DB_Error object on failure. + * + * @access private + */ + function _BCsequence($seqname) + { + // Obtain a user-level lock... this will release any previous + // application locks, but unlike LOCK TABLES, it does not abort + // the current transaction and is much less frequently used. + $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)"); + if (DB::isError($result)) { + return $result; + } + if ($result == 0) { + // Failed to get the lock, can't do the conversion, bail + // with a DB_ERROR_NOT_LOCKED error + return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED); + } + + $highest_id = $this->getOne("SELECT MAX(id) FROM ${seqname}"); + if (DB::isError($highest_id)) { + return $highest_id; + } + // This should kill all rows except the highest + // We should probably do something if $highest_id isn't + // numeric, but I'm at a loss as how to handle that... + $result = $this->query('DELETE FROM ' . $seqname + . " WHERE id <> $highest_id"); + if (DB::isError($result)) { + return $result; + } + + // If another thread has been waiting for this lock, + // it will go thru the above procedure, but will have no + // real effect + $result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')"); + if (DB::isError($result)) { + return $result; + } + return true; + } + + // }}} + // {{{ quoteIdentifier() + + /** + * Quotes a string so it can be safely used as a table or column name + * + * MySQL can't handle the backtick character (<kbd>`</kbd>) in + * table or column names. + * + * @param string $str identifier name to be quoted + * + * @return string quoted identifier string + * + * @see DB_common::quoteIdentifier() + * @since Method available since Release 1.6.0 + */ + function quoteIdentifier($str) + { + return '`' . $str . '`'; + } + + // }}} + // {{{ quote() + + /** + * @deprecated Deprecated in release 1.6.0 + */ + function quote($str) + { + return $this->quoteSmart($str); + } + + // }}} + // {{{ escapeSimple() + + /** + * Escapes a string according to the current DBMS's standards + * + * @param string $str the string to be escaped + * + * @return string the escaped string + * + * @see DB_common::quoteSmart() + * @since Method available since Release 1.6.0 + */ + function escapeSimple($str) + { + if (function_exists('mysql_real_escape_string')) { + return @mysql_real_escape_string($str, $this->connection); + } else { + return @mysql_escape_string($str); + } + } + + // }}} + // {{{ modifyQuery() + + /** + * Changes a query string for various DBMS specific reasons + * + * This little hack lets you know how many rows were deleted + * when running a "DELETE FROM table" query. Only implemented + * if the DB_PORTABILITY_DELETE_COUNT portability option is on. + * + * @param string $query the query string to modify + * + * @return string the modified query string + * + * @access protected + * @see DB_common::setOption() + */ + function modifyQuery($query) + { + if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) { + // "DELETE FROM table" gives 0 affected rows in MySQL. + // This little hack lets you know how many rows were deleted. + if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) { + $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/', + 'DELETE FROM \1 WHERE 1=1', $query); + } + } + return $query; + } + + // }}} + // {{{ modifyLimitQuery() + + /** + * Adds LIMIT clauses to a query string according to current DBMS standards + * + * @param string $query the query to modify + * @param int $from the row to start to fetching (0 = the first row) + * @param int $count the numbers of rows to fetch + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return string the query string with LIMIT clauses added + * + * @access protected + */ + function modifyLimitQuery($query, $from, $count, $params = array()) + { + if (DB::isManip($query)) { + return $query . " LIMIT $count"; + } else { + return $query . " LIMIT $from, $count"; + } + } + + // }}} + // {{{ mysqlRaiseError() + + /** + * Produces a DB_Error object regarding the current problem + * + * @param int $errno if the error is being manually raised pass a + * DB_ERROR* constant here. If this isn't passed + * the error information gathered from the DBMS. + * + * @return object the DB_Error object + * + * @see DB_common::raiseError(), + * DB_mysql::errorNative(), DB_common::errorCode() + */ + function mysqlRaiseError($errno = null) + { + if ($errno === null) { + if ($this->options['portability'] & DB_PORTABILITY_ERRORS) { + $this->errorcode_map[1022] = DB_ERROR_CONSTRAINT; + $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL; + $this->errorcode_map[1062] = DB_ERROR_CONSTRAINT; + } else { + // Doing this in case mode changes during runtime. + $this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS; + $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT; + $this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS; + } + $errno = $this->errorCode(mysql_errno($this->connection)); + } + return $this->raiseError($errno, null, null, null, + @mysql_errno($this->connection) . ' ** ' . + @mysql_error($this->connection)); + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error code produced by the last query + * + * @return int the DBMS' error code + */ + function errorNative() + { + return @mysql_errno($this->connection); + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * @param object|string $result DB_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::tableInfo() + */ + function tableInfo($result, $mode = null) + { + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = @mysql_list_fields($this->dsn['database'], + $result, $this->connection); + $got_string = true; + } elseif (isset($result->result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->result; + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_resource($id)) { + return $this->mysqlRaiseError(DB_ERROR_NEED_MORE_DATA); + } + + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $count = @mysql_num_fields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $res[$i] = array( + 'table' => $case_func(@mysql_field_table($id, $i)), + 'name' => $case_func(@mysql_field_name($id, $i)), + 'type' => @mysql_field_type($id, $i), + 'len' => @mysql_field_len($id, $i), + 'flags' => @mysql_field_flags($id, $i), + ); + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @mysql_free_result($id); + } + return $res; + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtains the query string needed for listing a given type of objects + * + * @param string $type the kind of objects you want to retrieve + * + * @return string the SQL query string or null if the driver doesn't + * support the object type requested + * + * @access protected + * @see DB_common::getListOf() + */ + function getSpecialQuery($type) + { + switch ($type) { + case 'tables': + return 'SHOW TABLES'; + case 'users': + return 'SELECT DISTINCT User FROM mysql.user'; + case 'databases': + return 'SHOW DATABASES'; + default: + return null; + } + } + + // }}} + +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/plugins/tidypics/lib/phpFlickr/PEAR/DB/pgsql.php b/plugins/tidypics/lib/phpFlickr/PEAR/DB/pgsql.php new file mode 100644 index 0000000000000000000000000000000000000000..1e58f48d65f4b6c8017588e369b325c92ac7ac26 --- /dev/null +++ b/plugins/tidypics/lib/phpFlickr/PEAR/DB/pgsql.php @@ -0,0 +1,1097 @@ +<?php + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * The PEAR DB driver for PHP's pgsql extension + * for interacting with PostgreSQL databases + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category Database + * @package DB + * @author Rui Hirokawa <hirokawa@php.net> + * @author Stig Bakken <ssb@php.net> + * @author Daniel Convissor <danielc@php.net> + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: pgsql.php 32 2005-08-01 06:21:02Z dancoulter $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB_common class so it can be extended from + */ +require_once 'DB/common.php'; + +/** + * The methods PEAR DB uses to interact with PHP's pgsql extension + * for interacting with PostgreSQL databases + * + * These methods overload the ones declared in DB_common. + * + * @category Database + * @package DB + * @author Rui Hirokawa <hirokawa@php.net> + * @author Stig Bakken <ssb@php.net> + * @author Daniel Convissor <danielc@php.net> + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_pgsql extends DB_common +{ + // {{{ properties + + /** + * The DB driver type (mysql, oci8, odbc, etc.) + * @var string + */ + var $phptype = 'pgsql'; + + /** + * The database syntax variant to be used (db2, access, etc.), if any + * @var string + */ + var $dbsyntax = 'pgsql'; + + /** + * The capabilities of this DB implementation + * + * The 'new_link' element contains the PHP version that first provided + * new_link support for this DBMS. Contains false if it's unsupported. + * + * Meaning of the 'limit' element: + * + 'emulate' = emulate with fetch row by number + * + 'alter' = alter the query + * + false = skip rows + * + * @var array + */ + var $features = array( + 'limit' => 'alter', + 'new_link' => '4.3.0', + 'numrows' => true, + 'pconnect' => true, + 'prepare' => false, + 'ssl' => true, + 'transactions' => true, + ); + + /** + * A mapping of native error codes to DB error codes + * @var array + */ + var $errorcode_map = array( + ); + + /** + * The raw database connection created by PHP + * @var resource + */ + var $connection; + + /** + * The DSN information for connecting to a database + * @var array + */ + var $dsn = array(); + + + /** + * Should data manipulation queries be committed automatically? + * @var bool + * @access private + */ + var $autocommit = true; + + /** + * The quantity of transactions begun + * + * {@internal While this is private, it can't actually be designated + * private in PHP 5 because it is directly accessed in the test suite.}} + * + * @var integer + * @access private + */ + var $transaction_opcount = 0; + + /** + * The number of rows affected by a data manipulation query + * @var integer + */ + var $affected = 0; + + /** + * The current row being looked at in fetchInto() + * @var array + * @access private + */ + var $row = array(); + + /** + * The number of rows in a given result set + * @var array + * @access private + */ + var $_num_rows = array(); + + + // }}} + // {{{ constructor + + /** + * This constructor calls <kbd>$this->DB_common()</kbd> + * + * @return void + */ + function DB_pgsql() + { + $this->DB_common(); + } + + // }}} + // {{{ connect() + + /** + * Connect to the database server, log in and open the database + * + * Don't call this method directly. Use DB::connect() instead. + * + * PEAR DB's pgsql driver supports the following extra DSN options: + * + connect_timeout How many seconds to wait for a connection to + * be established. Available since PEAR DB 1.7.0. + * + new_link If set to true, causes subsequent calls to + * connect() to return a new connection link + * instead of the existing one. WARNING: this is + * not portable to other DBMS's. Available only + * if PHP is >= 4.3.0 and PEAR DB is >= 1.7.0. + * + options Command line options to be sent to the server. + * Available since PEAR DB 1.6.4. + * + service Specifies a service name in pg_service.conf that + * holds additional connection parameters. + * Available since PEAR DB 1.7.0. + * + sslmode How should SSL be used when connecting? Values: + * disable, allow, prefer or require. + * Available since PEAR DB 1.7.0. + * + tty This was used to specify where to send server + * debug output. Available since PEAR DB 1.6.4. + * + * Example of connecting to a new link via a socket: + * <code> + * require_once 'DB.php'; + * + * $dsn = 'pgsql://user:pass@unix(/tmp)/dbname?new_link=true'; + * $options = array( + * 'portability' => DB_PORTABILITY_ALL, + * ); + * + * $db =& DB::connect($dsn, $options); + * if (PEAR::isError($db)) { + * die($db->getMessage()); + * } + * </code> + * + * @param array $dsn the data source name + * @param bool $persistent should the connection be persistent? + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @link http://www.postgresql.org/docs/current/static/libpq.html#LIBPQ-CONNECT + */ + function connect($dsn, $persistent = false) + { + if (!PEAR::loadExtension('pgsql')) { + return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); + } + + $this->dsn = $dsn; + if ($dsn['dbsyntax']) { + $this->dbsyntax = $dsn['dbsyntax']; + } + + $protocol = $dsn['protocol'] ? $dsn['protocol'] : 'tcp'; + + $params = array(''); + if ($protocol == 'tcp') { + if ($dsn['hostspec']) { + $params[0] .= 'host=' . $dsn['hostspec']; + } + if ($dsn['port']) { + $params[0] .= ' port=' . $dsn['port']; + } + } elseif ($protocol == 'unix') { + // Allow for pg socket in non-standard locations. + if ($dsn['socket']) { + $params[0] .= 'host=' . $dsn['socket']; + } + if ($dsn['port']) { + $params[0] .= ' port=' . $dsn['port']; + } + } + if ($dsn['database']) { + $params[0] .= ' dbname=\'' . addslashes($dsn['database']) . '\''; + } + if ($dsn['username']) { + $params[0] .= ' user=\'' . addslashes($dsn['username']) . '\''; + } + if ($dsn['password']) { + $params[0] .= ' password=\'' . addslashes($dsn['password']) . '\''; + } + if (!empty($dsn['options'])) { + $params[0] .= ' options=' . $dsn['options']; + } + if (!empty($dsn['tty'])) { + $params[0] .= ' tty=' . $dsn['tty']; + } + if (!empty($dsn['connect_timeout'])) { + $params[0] .= ' connect_timeout=' . $dsn['connect_timeout']; + } + if (!empty($dsn['sslmode'])) { + $params[0] .= ' sslmode=' . $dsn['sslmode']; + } + if (!empty($dsn['service'])) { + $params[0] .= ' service=' . $dsn['service']; + } + + if (isset($dsn['new_link']) + && ($dsn['new_link'] == 'true' || $dsn['new_link'] === true)) + { + if (version_compare(phpversion(), '4.3.0', '>=')) { + $params[] = PGSQL_CONNECT_FORCE_NEW; + } + } + + $connect_function = $persistent ? 'pg_pconnect' : 'pg_connect'; + + $ini = ini_get('track_errors'); + $php_errormsg = ''; + if ($ini) { + $this->connection = @call_user_func_array($connect_function, + $params); + } else { + ini_set('track_errors', 1); + $this->connection = @call_user_func_array($connect_function, + $params); + ini_set('track_errors', $ini); + } + + if (!$this->connection) { + return $this->raiseError(DB_ERROR_CONNECT_FAILED, + null, null, null, + $php_errormsg); + } + return DB_OK; + } + + // }}} + // {{{ disconnect() + + /** + * Disconnects from the database server + * + * @return bool TRUE on success, FALSE on failure + */ + function disconnect() + { + $ret = @pg_close($this->connection); + $this->connection = null; + return $ret; + } + + // }}} + // {{{ simpleQuery() + + /** + * Sends a query to the database server + * + * @param string the SQL query string + * + * @return mixed + a PHP result resrouce for successful SELECT queries + * + the DB_OK constant for other successful queries + * + a DB_Error object on failure + */ + function simpleQuery($query) + { + $ismanip = DB::isManip($query); + $this->last_query = $query; + $query = $this->modifyQuery($query); + if (!$this->autocommit && $ismanip) { + if ($this->transaction_opcount == 0) { + $result = @pg_exec($this->connection, 'begin;'); + if (!$result) { + return $this->pgsqlRaiseError(); + } + } + $this->transaction_opcount++; + } + $result = @pg_exec($this->connection, $query); + if (!$result) { + return $this->pgsqlRaiseError(); + } + // Determine which queries that should return data, and which + // should return an error code only. + if ($ismanip) { + $this->affected = @pg_affected_rows($result); + return DB_OK; + } elseif (preg_match('/^\s*\(*\s*(SELECT|EXPLAIN|SHOW)\s/si', $query)) { + /* PostgreSQL commands: + ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY, + CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH, + GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET, + REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW, + UNLISTEN, UPDATE, VACUUM + */ + $this->row[(int)$result] = 0; // reset the row counter. + $numrows = $this->numRows($result); + if (is_object($numrows)) { + return $numrows; + } + $this->_num_rows[(int)$result] = $numrows; + $this->affected = 0; + return $result; + } else { + $this->affected = 0; + return DB_OK; + } + } + + // }}} + // {{{ nextResult() + + /** + * Move the internal pgsql result pointer to the next available result + * + * @param a valid fbsql result resource + * + * @access public + * + * @return true if a result is available otherwise return false + */ + function nextResult($result) + { + return false; + } + + // }}} + // {{{ fetchInto() + + /** + * Places a row from the result set into the given array + * + * Formating of the array and the data therein are configurable. + * See DB_result::fetchInto() for more information. + * + * This method is not meant to be called directly. Use + * DB_result::fetchInto() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result the query result resource + * @param array $arr the referenced array to put the data in + * @param int $fetchmode how the resulting array should be indexed + * @param int $rownum the row number to fetch (0 = first row) + * + * @return mixed DB_OK on success, NULL when the end of a result set is + * reached or on failure + * + * @see DB_result::fetchInto() + */ + function fetchInto($result, &$arr, $fetchmode, $rownum = null) + { + $result_int = (int)$result; + $rownum = ($rownum !== null) ? $rownum : $this->row[$result_int]; + if ($rownum >= $this->_num_rows[$result_int]) { + return null; + } + if ($fetchmode & DB_FETCHMODE_ASSOC) { + $arr = @pg_fetch_array($result, $rownum, PGSQL_ASSOC); + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { + $arr = array_change_key_case($arr, CASE_LOWER); + } + } else { + $arr = @pg_fetch_row($result, $rownum); + } + if (!$arr) { + return null; + } + if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { + $this->_rtrimArrayValues($arr); + } + if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { + $this->_convertNullArrayValuesToEmpty($arr); + } + $this->row[$result_int] = ++$rownum; + return DB_OK; + } + + // }}} + // {{{ freeResult() + + /** + * Deletes the result set and frees the memory occupied by the result set + * + * This method is not meant to be called directly. Use + * DB_result::free() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_result::free() + */ + function freeResult($result) + { + if (is_resource($result)) { + unset($this->row[(int)$result]); + unset($this->_num_rows[(int)$result]); + $this->affected = 0; + return @pg_freeresult($result); + } + return false; + } + + // }}} + // {{{ quote() + + /** + * @deprecated Deprecated in release 1.6.0 + * @internal + */ + function quote($str) + { + return $this->quoteSmart($str); + } + + // }}} + // {{{ quoteSmart() + + /** + * Formats input so it can be safely used in a query + * + * @param mixed $in the data to be formatted + * + * @return mixed the formatted data. The format depends on the input's + * PHP type: + * + null = the string <samp>NULL</samp> + * + boolean = string <samp>TRUE</samp> or <samp>FALSE</samp> + * + integer or double = the unquoted number + * + other (including strings and numeric strings) = + * the data escaped according to MySQL's settings + * then encapsulated between single quotes + * + * @see DB_common::quoteSmart() + * @since Method available since Release 1.6.0 + */ + function quoteSmart($in) + { + if (is_int($in) || is_double($in)) { + return $in; + } elseif (is_bool($in)) { + return $in ? 'TRUE' : 'FALSE'; + } elseif (is_null($in)) { + return 'NULL'; + } else { + return "'" . $this->escapeSimple($in) . "'"; + } + } + + // }}} + // {{{ escapeSimple() + + /** + * Escapes a string according to the current DBMS's standards + * + * {@internal PostgreSQL treats a backslash as an escape character, + * so they are escaped as well. + * + * Not using pg_escape_string() yet because it requires PostgreSQL + * to be at version 7.2 or greater.}} + * + * @param string $str the string to be escaped + * + * @return string the escaped string + * + * @see DB_common::quoteSmart() + * @since Method available since Release 1.6.0 + */ + function escapeSimple($str) + { + return str_replace("'", "''", str_replace('\\', '\\\\', $str)); + } + + // }}} + // {{{ numCols() + + /** + * Gets the number of columns in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numCols() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of columns. A DB_Error object on failure. + * + * @see DB_result::numCols() + */ + function numCols($result) + { + $cols = @pg_numfields($result); + if (!$cols) { + return $this->pgsqlRaiseError(); + } + return $cols; + } + + // }}} + // {{{ numRows() + + /** + * Gets the number of rows in a result set + * + * This method is not meant to be called directly. Use + * DB_result::numRows() instead. It can't be declared "protected" + * because DB_result is a separate object. + * + * @param resource $result PHP's query result resource + * + * @return int the number of rows. A DB_Error object on failure. + * + * @see DB_result::numRows() + */ + function numRows($result) + { + $rows = @pg_numrows($result); + if ($rows === null) { + return $this->pgsqlRaiseError(); + } + return $rows; + } + + // }}} + // {{{ autoCommit() + + /** + * Enables or disables automatic commits + * + * @param bool $onoff true turns it on, false turns it off + * + * @return int DB_OK on success. A DB_Error object if the driver + * doesn't support auto-committing transactions. + */ + function autoCommit($onoff = false) + { + // XXX if $this->transaction_opcount > 0, we should probably + // issue a warning here. + $this->autocommit = $onoff ? true : false; + return DB_OK; + } + + // }}} + // {{{ commit() + + /** + * Commits the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function commit() + { + if ($this->transaction_opcount > 0) { + // (disabled) hack to shut up error messages from libpq.a + //@fclose(@fopen("php://stderr", "w")); + $result = @pg_exec($this->connection, 'end;'); + $this->transaction_opcount = 0; + if (!$result) { + return $this->pgsqlRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ rollback() + + /** + * Reverts the current transaction + * + * @return int DB_OK on success. A DB_Error object on failure. + */ + function rollback() + { + if ($this->transaction_opcount > 0) { + $result = @pg_exec($this->connection, 'abort;'); + $this->transaction_opcount = 0; + if (!$result) { + return $this->pgsqlRaiseError(); + } + } + return DB_OK; + } + + // }}} + // {{{ affectedRows() + + /** + * Determines the number of rows affected by a data maniuplation query + * + * 0 is returned for queries that don't manipulate data. + * + * @return int the number of rows. A DB_Error object on failure. + */ + function affectedRows() + { + return $this->affected; + } + + // }}} + // {{{ nextId() + + /** + * Returns the next free id in a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true, the seqence is automatically + * created if it does not exist + * + * @return int the next id number in the sequence. + * A DB_Error object on failure. + * + * @see DB_common::nextID(), DB_common::getSequenceName(), + * DB_pgsql::createSequence(), DB_pgsql::dropSequence() + */ + function nextId($seq_name, $ondemand = true) + { + $seqname = $this->getSequenceName($seq_name); + $repeat = false; + do { + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result =& $this->query("SELECT NEXTVAL('${seqname}')"); + $this->popErrorHandling(); + if ($ondemand && DB::isError($result) && + $result->getCode() == DB_ERROR_NOSUCHTABLE) { + $repeat = true; + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $result = $this->createSequence($seq_name); + $this->popErrorHandling(); + if (DB::isError($result)) { + return $this->raiseError($result); + } + } else { + $repeat = false; + } + } while ($repeat); + if (DB::isError($result)) { + return $this->raiseError($result); + } + $arr = $result->fetchRow(DB_FETCHMODE_ORDERED); + $result->free(); + return $arr[0]; + } + + // }}} + // {{{ createSequence() + + /** + * Creates a new sequence + * + * @param string $seq_name name of the new sequence + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::createSequence(), DB_common::getSequenceName(), + * DB_pgsql::nextID(), DB_pgsql::dropSequence() + */ + function createSequence($seq_name) + { + $seqname = $this->getSequenceName($seq_name); + $result = $this->query("CREATE SEQUENCE ${seqname}"); + return $result; + } + + // }}} + // {{{ dropSequence() + + /** + * Deletes a sequence + * + * @param string $seq_name name of the sequence to be deleted + * + * @return int DB_OK on success. A DB_Error object on failure. + * + * @see DB_common::dropSequence(), DB_common::getSequenceName(), + * DB_pgsql::nextID(), DB_pgsql::createSequence() + */ + function dropSequence($seq_name) + { + return $this->query('DROP SEQUENCE ' + . $this->getSequenceName($seq_name)); + } + + // }}} + // {{{ modifyLimitQuery() + + /** + * Adds LIMIT clauses to a query string according to current DBMS standards + * + * @param string $query the query to modify + * @param int $from the row to start to fetching (0 = the first row) + * @param int $count the numbers of rows to fetch + * @param mixed $params array, string or numeric data to be used in + * execution of the statement. Quantity of items + * passed must match quantity of placeholders in + * query: meaning 1 placeholder for non-array + * parameters or 1 placeholder per array element. + * + * @return string the query string with LIMIT clauses added + * + * @access protected + */ + function modifyLimitQuery($query, $from, $count, $params = array()) + { + return "$query LIMIT $count OFFSET $from"; + } + + // }}} + // {{{ pgsqlRaiseError() + + /** + * Produces a DB_Error object regarding the current problem + * + * @param int $errno if the error is being manually raised pass a + * DB_ERROR* constant here. If this isn't passed + * the error information gathered from the DBMS. + * + * @return object the DB_Error object + * + * @see DB_common::raiseError(), + * DB_pgsql::errorNative(), DB_pgsql::errorCode() + */ + function pgsqlRaiseError($errno = null) + { + $native = $this->errorNative(); + if ($errno === null) { + $errno = $this->errorCode($native); + } + return $this->raiseError($errno, null, null, null, $native); + } + + // }}} + // {{{ errorNative() + + /** + * Gets the DBMS' native error message produced by the last query + * + * {@internal Error messages are used instead of error codes + * in order to support older versions of PostgreSQL.}} + * + * @return string the DBMS' error message + */ + function errorNative() + { + return @pg_errormessage($this->connection); + } + + // }}} + // {{{ errorCode() + + /** + * Determines PEAR::DB error code from the database's text error message. + * + * @param string $errormsg error message returned from the database + * @return integer an error number from a DB error constant + */ + function errorCode($errormsg) + { + static $error_regexps; + if (!isset($error_regexps)) { + $error_regexps = array( + '/(relation|sequence|table).*does not exist|class .* not found/i' + => DB_ERROR_NOSUCHTABLE, + '/index .* does not exist/' + => DB_ERROR_NOT_FOUND, + '/column .* does not exist/i' + => DB_ERROR_NOSUCHFIELD, + '/relation .* already exists/i' + => DB_ERROR_ALREADY_EXISTS, + '/(divide|division) by zero$/i' + => DB_ERROR_DIVZERO, + '/pg_atoi: error in .*: can\'t parse /i' + => DB_ERROR_INVALID_NUMBER, + '/invalid input syntax for( type)? (integer|numeric)/i' + => DB_ERROR_INVALID_NUMBER, + '/value .* is out of range for type \w*int/i' + => DB_ERROR_INVALID_NUMBER, + '/integer out of range/i' + => DB_ERROR_INVALID_NUMBER, + '/value too long for type character/i' + => DB_ERROR_INVALID, + '/attribute .* not found|relation .* does not have attribute/i' + => DB_ERROR_NOSUCHFIELD, + '/column .* specified in USING clause does not exist in (left|right) table/i' + => DB_ERROR_NOSUCHFIELD, + '/parser: parse error at or near/i' + => DB_ERROR_SYNTAX, + '/syntax error at/' + => DB_ERROR_SYNTAX, + '/column reference .* is ambiguous/i' + => DB_ERROR_SYNTAX, + '/permission denied/' + => DB_ERROR_ACCESS_VIOLATION, + '/violates not-null constraint/' + => DB_ERROR_CONSTRAINT_NOT_NULL, + '/violates [\w ]+ constraint/' + => DB_ERROR_CONSTRAINT, + '/referential integrity violation/' + => DB_ERROR_CONSTRAINT, + '/more expressions than target columns/i' + => DB_ERROR_VALUE_COUNT_ON_ROW, + ); + } + foreach ($error_regexps as $regexp => $code) { + if (preg_match($regexp, $errormsg)) { + return $code; + } + } + // Fall back to DB_ERROR if there was no mapping. + return DB_ERROR; + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * NOTE: only supports 'table' and 'flags' if <var>$result</var> + * is a table name. + * + * @param object|string $result DB_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode a valid tableInfo mode + * + * @return array an associative array with the information requested. + * A DB_Error object on failure. + * + * @see DB_common::tableInfo() + */ + function tableInfo($result, $mode = null) + { + if (is_string($result)) { + /* + * Probably received a table name. + * Create a result resource identifier. + */ + $id = @pg_exec($this->connection, "SELECT * FROM $result LIMIT 0"); + $got_string = true; + } elseif (isset($result->result)) { + /* + * Probably received a result object. + * Extract the result resource identifier. + */ + $id = $result->result; + $got_string = false; + } else { + /* + * Probably received a result resource identifier. + * Copy it. + * Deprecated. Here for compatibility only. + */ + $id = $result; + $got_string = false; + } + + if (!is_resource($id)) { + return $this->pgsqlRaiseError(DB_ERROR_NEED_MORE_DATA); + } + + if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { + $case_func = 'strtolower'; + } else { + $case_func = 'strval'; + } + + $count = @pg_numfields($id); + $res = array(); + + if ($mode) { + $res['num_fields'] = $count; + } + + for ($i = 0; $i < $count; $i++) { + $res[$i] = array( + 'table' => $got_string ? $case_func($result) : '', + 'name' => $case_func(@pg_fieldname($id, $i)), + 'type' => @pg_fieldtype($id, $i), + 'len' => @pg_fieldsize($id, $i), + 'flags' => $got_string + ? $this->_pgFieldFlags($id, $i, $result) + : '', + ); + if ($mode & DB_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & DB_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + // free the result only if we were called on a table + if ($got_string) { + @pg_freeresult($id); + } + return $res; + } + + // }}} + // {{{ _pgFieldFlags() + + /** + * Get a column's flags + * + * Supports "not_null", "default_value", "primary_key", "unique_key" + * and "multiple_key". The default value is passed through + * rawurlencode() in case there are spaces in it. + * + * @param int $resource the PostgreSQL result identifier + * @param int $num_field the field number + * + * @return string the flags + * + * @access private + */ + function _pgFieldFlags($resource, $num_field, $table_name) + { + $field_name = @pg_fieldname($resource, $num_field); + + $result = @pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef + FROM pg_attribute f, pg_class tab, pg_type typ + WHERE tab.relname = typ.typname + AND typ.typrelid = f.attrelid + AND f.attname = '$field_name' + AND tab.relname = '$table_name'"); + if (@pg_numrows($result) > 0) { + $row = @pg_fetch_row($result, 0); + $flags = ($row[0] == 't') ? 'not_null ' : ''; + + if ($row[1] == 't') { + $result = @pg_exec($this->connection, "SELECT a.adsrc + FROM pg_attribute f, pg_class tab, pg_type typ, pg_attrdef a + WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid + AND f.attrelid = a.adrelid AND f.attname = '$field_name' + AND tab.relname = '$table_name' AND f.attnum = a.adnum"); + $row = @pg_fetch_row($result, 0); + $num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]); + $flags .= 'default_' . rawurlencode($num) . ' '; + } + } else { + $flags = ''; + } + $result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey + FROM pg_attribute f, pg_class tab, pg_type typ, pg_index i + WHERE tab.relname = typ.typname + AND typ.typrelid = f.attrelid + AND f.attrelid = i.indrelid + AND f.attname = '$field_name' + AND tab.relname = '$table_name'"); + $count = @pg_numrows($result); + + for ($i = 0; $i < $count ; $i++) { + $row = @pg_fetch_row($result, $i); + $keys = explode(' ', $row[2]); + + if (in_array($num_field + 1, $keys)) { + $flags .= ($row[0] == 't' && $row[1] == 'f') ? 'unique_key ' : ''; + $flags .= ($row[1] == 't') ? 'primary_key ' : ''; + if (count($keys) > 1) + $flags .= 'multiple_key '; + } + } + + return trim($flags); + } + + // }}} + // {{{ getSpecialQuery() + + /** + * Obtains the query string needed for listing a given type of objects + * + * @param string $type the kind of objects you want to retrieve + * + * @return string the SQL query string or null if the driver doesn't + * support the object type requested + * + * @access protected + * @see DB_common::getListOf() + */ + function getSpecialQuery($type) + { + switch ($type) { + case 'tables': + return 'SELECT c.relname AS "Name"' + . ' FROM pg_class c, pg_user u' + . ' WHERE c.relowner = u.usesysid' + . " AND c.relkind = 'r'" + . ' AND NOT EXISTS' + . ' (SELECT 1 FROM pg_views' + . ' WHERE viewname = c.relname)' + . " AND c.relname !~ '^(pg_|sql_)'" + . ' UNION' + . ' SELECT c.relname AS "Name"' + . ' FROM pg_class c' + . " WHERE c.relkind = 'r'" + . ' AND NOT EXISTS' + . ' (SELECT 1 FROM pg_views' + . ' WHERE viewname = c.relname)' + . ' AND NOT EXISTS' + . ' (SELECT 1 FROM pg_user' + . ' WHERE usesysid = c.relowner)' + . " AND c.relname !~ '^pg_'"; + case 'schema.tables': + return "SELECT schemaname || '.' || tablename" + . ' AS "Name"' + . ' FROM pg_catalog.pg_tables' + . ' WHERE schemaname NOT IN' + . " ('pg_catalog', 'information_schema', 'pg_toast')"; + case 'views': + // Table cols: viewname | viewowner | definition + return 'SELECT viewname from pg_views WHERE schemaname' + . " NOT IN ('information_schema', 'pg_catalog')"; + case 'users': + // cols: usename |usesysid|usecreatedb|usetrace|usesuper|usecatupd|passwd |valuntil + return 'SELECT usename FROM pg_user'; + case 'databases': + return 'SELECT datname FROM pg_database'; + case 'functions': + case 'procedures': + return 'SELECT proname FROM pg_proc WHERE proowner <> 1'; + default: + return null; + } + } + + // }}} + +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/plugins/tidypics/lib/phpFlickr/PEAR/DB/storage.php b/plugins/tidypics/lib/phpFlickr/PEAR/DB/storage.php new file mode 100644 index 0000000000000000000000000000000000000000..f597b36d7080c2d0f2a78d7a0bdeae96a069269a --- /dev/null +++ b/plugins/tidypics/lib/phpFlickr/PEAR/DB/storage.php @@ -0,0 +1,504 @@ +<?php + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * Provides an object interface to a table row + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category Database + * @package DB + * @author Stig Bakken <stig@php.net> + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: storage.php 32 2005-08-01 06:21:02Z dancoulter $ + * @link http://pear.php.net/package/DB + */ + +/** + * Obtain the DB class so it can be extended from + */ +require_once 'DB.php'; + +/** + * Provides an object interface to a table row + * + * It lets you add, delete and change rows using objects rather than SQL + * statements. + * + * @category Database + * @package DB + * @author Stig Bakken <stig@php.net> + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/DB + */ +class DB_storage extends PEAR +{ + // {{{ properties + + /** the name of the table (or view, if the backend database supports + updates in views) we hold data from */ + var $_table = null; + + /** which column(s) in the table contains primary keys, can be a + string for single-column primary keys, or an array of strings + for multiple-column primary keys */ + var $_keycolumn = null; + + /** DB connection handle used for all transactions */ + var $_dbh = null; + + /** an assoc with the names of database fields stored as properties + in this object */ + var $_properties = array(); + + /** an assoc with the names of the properties in this object that + have been changed since they were fetched from the database */ + var $_changes = array(); + + /** flag that decides if data in this object can be changed. + objects that don't have their table's key column in their + property lists will be flagged as read-only. */ + var $_readonly = false; + + /** function or method that implements a validator for fields that + are set, this validator function returns true if the field is + valid, false if not */ + var $_validator = null; + + // }}} + // {{{ constructor + + /** + * Constructor + * + * @param $table string the name of the database table + * + * @param $keycolumn mixed string with name of key column, or array of + * strings if the table has a primary key of more than one column + * + * @param $dbh object database connection object + * + * @param $validator mixed function or method used to validate + * each new value, called with three parameters: the name of the + * field/column that is changing, a reference to the new value and + * a reference to this object + * + */ + function DB_storage($table, $keycolumn, &$dbh, $validator = null) + { + $this->PEAR('DB_Error'); + $this->_table = $table; + $this->_keycolumn = $keycolumn; + $this->_dbh = $dbh; + $this->_readonly = false; + $this->_validator = $validator; + } + + // }}} + // {{{ _makeWhere() + + /** + * Utility method to build a "WHERE" clause to locate ourselves in + * the table. + * + * XXX future improvement: use rowids? + * + * @access private + */ + function _makeWhere($keyval = null) + { + if (is_array($this->_keycolumn)) { + if ($keyval === null) { + for ($i = 0; $i < sizeof($this->_keycolumn); $i++) { + $keyval[] = $this->{$this->_keycolumn[$i]}; + } + } + $whereclause = ''; + for ($i = 0; $i < sizeof($this->_keycolumn); $i++) { + if ($i > 0) { + $whereclause .= ' AND '; + } + $whereclause .= $this->_keycolumn[$i]; + if (is_null($keyval[$i])) { + // there's not much point in having a NULL key, + // but we support it anyway + $whereclause .= ' IS NULL'; + } else { + $whereclause .= ' = ' . $this->_dbh->quote($keyval[$i]); + } + } + } else { + if ($keyval === null) { + $keyval = @$this->{$this->_keycolumn}; + } + $whereclause = $this->_keycolumn; + if (is_null($keyval)) { + // there's not much point in having a NULL key, + // but we support it anyway + $whereclause .= ' IS NULL'; + } else { + $whereclause .= ' = ' . $this->_dbh->quote($keyval); + } + } + return $whereclause; + } + + // }}} + // {{{ setup() + + /** + * Method used to initialize a DB_storage object from the + * configured table. + * + * @param $keyval mixed the key[s] of the row to fetch (string or array) + * + * @return int DB_OK on success, a DB error if not + */ + function setup($keyval) + { + $whereclause = $this->_makeWhere($keyval); + $query = 'SELECT * FROM ' . $this->_table . ' WHERE ' . $whereclause; + $sth = $this->_dbh->query($query); + if (DB::isError($sth)) { + return $sth; + } + $row = $sth->fetchRow(DB_FETCHMODE_ASSOC); + if (DB::isError($row)) { + return $row; + } + if (!$row) { + return $this->raiseError(null, DB_ERROR_NOT_FOUND, null, null, + $query, null, true); + } + foreach ($row as $key => $value) { + $this->_properties[$key] = true; + $this->$key = $value; + } + return DB_OK; + } + + // }}} + // {{{ insert() + + /** + * Create a new (empty) row in the configured table for this + * object. + */ + function insert($newpk) + { + if (is_array($this->_keycolumn)) { + $primarykey = $this->_keycolumn; + } else { + $primarykey = array($this->_keycolumn); + } + settype($newpk, "array"); + for ($i = 0; $i < sizeof($primarykey); $i++) { + $pkvals[] = $this->_dbh->quote($newpk[$i]); + } + + $sth = $this->_dbh->query("INSERT INTO $this->_table (" . + implode(",", $primarykey) . ") VALUES(" . + implode(",", $pkvals) . ")"); + if (DB::isError($sth)) { + return $sth; + } + if (sizeof($newpk) == 1) { + $newpk = $newpk[0]; + } + $this->setup($newpk); + } + + // }}} + // {{{ toString() + + /** + * Output a simple description of this DB_storage object. + * @return string object description + */ + function toString() + { + $info = strtolower(get_class($this)); + $info .= " (table="; + $info .= $this->_table; + $info .= ", keycolumn="; + if (is_array($this->_keycolumn)) { + $info .= "(" . implode(",", $this->_keycolumn) . ")"; + } else { + $info .= $this->_keycolumn; + } + $info .= ", dbh="; + if (is_object($this->_dbh)) { + $info .= $this->_dbh->toString(); + } else { + $info .= "null"; + } + $info .= ")"; + if (sizeof($this->_properties)) { + $info .= " [loaded, key="; + $keyname = $this->_keycolumn; + if (is_array($keyname)) { + $info .= "("; + for ($i = 0; $i < sizeof($keyname); $i++) { + if ($i > 0) { + $info .= ","; + } + $info .= $this->$keyname[$i]; + } + $info .= ")"; + } else { + $info .= $this->$keyname; + } + $info .= "]"; + } + if (sizeof($this->_changes)) { + $info .= " [modified]"; + } + return $info; + } + + // }}} + // {{{ dump() + + /** + * Dump the contents of this object to "standard output". + */ + function dump() + { + foreach ($this->_properties as $prop => $foo) { + print "$prop = "; + print htmlentities($this->$prop); + print "<br />\n"; + } + } + + // }}} + // {{{ &create() + + /** + * Static method used to create new DB storage objects. + * @param $data assoc. array where the keys are the names + * of properties/columns + * @return object a new instance of DB_storage or a subclass of it + */ + function &create($table, &$data) + { + $classname = strtolower(get_class($this)); + $obj =& new $classname($table); + foreach ($data as $name => $value) { + $obj->_properties[$name] = true; + $obj->$name = &$value; + } + return $obj; + } + + // }}} + // {{{ loadFromQuery() + + /** + * Loads data into this object from the given query. If this + * object already contains table data, changes will be saved and + * the object re-initialized first. + * + * @param $query SQL query + * + * @param $params parameter list in case you want to use + * prepare/execute mode + * + * @return int DB_OK on success, DB_WARNING_READ_ONLY if the + * returned object is read-only (because the object's specified + * key column was not found among the columns returned by $query), + * or another DB error code in case of errors. + */ +// XXX commented out for now +/* + function loadFromQuery($query, $params = null) + { + if (sizeof($this->_properties)) { + if (sizeof($this->_changes)) { + $this->store(); + $this->_changes = array(); + } + $this->_properties = array(); + } + $rowdata = $this->_dbh->getRow($query, DB_FETCHMODE_ASSOC, $params); + if (DB::isError($rowdata)) { + return $rowdata; + } + reset($rowdata); + $found_keycolumn = false; + while (list($key, $value) = each($rowdata)) { + if ($key == $this->_keycolumn) { + $found_keycolumn = true; + } + $this->_properties[$key] = true; + $this->$key = &$value; + unset($value); // have to unset, or all properties will + // refer to the same value + } + if (!$found_keycolumn) { + $this->_readonly = true; + return DB_WARNING_READ_ONLY; + } + return DB_OK; + } + */ + + // }}} + // {{{ set() + + /** + * Modify an attriute value. + */ + function set($property, $newvalue) + { + // only change if $property is known and object is not + // read-only + if ($this->_readonly) { + return $this->raiseError(null, DB_WARNING_READ_ONLY, null, + null, null, null, true); + } + if (@isset($this->_properties[$property])) { + if (empty($this->_validator)) { + $valid = true; + } else { + $valid = @call_user_func($this->_validator, + $this->_table, + $property, + $newvalue, + $this->$property, + $this); + } + if ($valid) { + $this->$property = $newvalue; + if (empty($this->_changes[$property])) { + $this->_changes[$property] = 0; + } else { + $this->_changes[$property]++; + } + } else { + return $this->raiseError(null, DB_ERROR_INVALID, null, + null, "invalid field: $property", + null, true); + } + return true; + } + return $this->raiseError(null, DB_ERROR_NOSUCHFIELD, null, + null, "unknown field: $property", + null, true); + } + + // }}} + // {{{ &get() + + /** + * Fetch an attribute value. + * + * @param string attribute name + * + * @return attribute contents, or null if the attribute name is + * unknown + */ + function &get($property) + { + // only return if $property is known + if (isset($this->_properties[$property])) { + return $this->$property; + } + $tmp = null; + return $tmp; + } + + // }}} + // {{{ _DB_storage() + + /** + * Destructor, calls DB_storage::store() if there are changes + * that are to be kept. + */ + function _DB_storage() + { + if (sizeof($this->_changes)) { + $this->store(); + } + $this->_properties = array(); + $this->_changes = array(); + $this->_table = null; + } + + // }}} + // {{{ store() + + /** + * Stores changes to this object in the database. + * + * @return DB_OK or a DB error + */ + function store() + { + foreach ($this->_changes as $name => $foo) { + $params[] = &$this->$name; + $vars[] = $name . ' = ?'; + } + if ($vars) { + $query = 'UPDATE ' . $this->_table . ' SET ' . + implode(', ', $vars) . ' WHERE ' . + $this->_makeWhere(); + $stmt = $this->_dbh->prepare($query); + $res = $this->_dbh->execute($stmt, $params); + if (DB::isError($res)) { + return $res; + } + $this->_changes = array(); + } + return DB_OK; + } + + // }}} + // {{{ remove() + + /** + * Remove the row represented by this object from the database. + * + * @return mixed DB_OK or a DB error + */ + function remove() + { + if ($this->_readonly) { + return $this->raiseError(null, DB_WARNING_READ_ONLY, null, + null, null, null, true); + } + $query = 'DELETE FROM ' . $this->_table .' WHERE '. + $this->_makeWhere(); + $res = $this->_dbh->query($query); + if (DB::isError($res)) { + return $res; + } + foreach ($this->_properties as $prop => $foo) { + unset($this->$prop); + } + $this->_properties = array(); + $this->_changes = array(); + return DB_OK; + } + + // }}} +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + +?> diff --git a/plugins/tidypics/lib/phpFlickr/PEAR/HTTP/Request.php b/plugins/tidypics/lib/phpFlickr/PEAR/HTTP/Request.php new file mode 100644 index 0000000000000000000000000000000000000000..55e227b3a9ba09c8881cfa505c4064b8b7566709 --- /dev/null +++ b/plugins/tidypics/lib/phpFlickr/PEAR/HTTP/Request.php @@ -0,0 +1,1484 @@ +<?php +/** + * Class for performing HTTP requests + * + * PHP versions 4 and 5 + * + * LICENSE: + * + * Copyright (c) 2002-2007, Richard Heyes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * o Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * o Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * o The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTTP + * @package HTTP_Request + * @author Richard Heyes <richard@phpguru.org> + * @author Alexey Borzov <avb@php.net> + * @copyright 2002-2007 Richard Heyes + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Request.php 127 2008-01-17 20:21:37Z dcoulter $ + * @link http://pear.php.net/package/HTTP_Request/ + */ + +/** + * PEAR and PEAR_Error classes (for error handling) + */ +require_once 'PEAR.php'; +/** + * Socket class + */ +require_once 'Net/Socket.php'; +/** + * URL handling class + */ +require_once 'Net/URL.php'; + +/**#@+ + * Constants for HTTP request methods + */ +define('HTTP_REQUEST_METHOD_GET', 'GET', true); +define('HTTP_REQUEST_METHOD_HEAD', 'HEAD', true); +define('HTTP_REQUEST_METHOD_POST', 'POST', true); +define('HTTP_REQUEST_METHOD_PUT', 'PUT', true); +define('HTTP_REQUEST_METHOD_DELETE', 'DELETE', true); +define('HTTP_REQUEST_METHOD_OPTIONS', 'OPTIONS', true); +define('HTTP_REQUEST_METHOD_TRACE', 'TRACE', true); +/**#@-*/ + +/**#@+ + * Constants for HTTP request error codes + */ +define('HTTP_REQUEST_ERROR_FILE', 1); +define('HTTP_REQUEST_ERROR_URL', 2); +define('HTTP_REQUEST_ERROR_PROXY', 4); +define('HTTP_REQUEST_ERROR_REDIRECTS', 8); +define('HTTP_REQUEST_ERROR_RESPONSE', 16); +define('HTTP_REQUEST_ERROR_GZIP_METHOD', 32); +define('HTTP_REQUEST_ERROR_GZIP_READ', 64); +define('HTTP_REQUEST_ERROR_GZIP_DATA', 128); +define('HTTP_REQUEST_ERROR_GZIP_CRC', 256); +/**#@-*/ + +/**#@+ + * Constants for HTTP protocol versions + */ +define('HTTP_REQUEST_HTTP_VER_1_0', '1.0', true); +define('HTTP_REQUEST_HTTP_VER_1_1', '1.1', true); +/**#@-*/ + +if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) { + /** + * Whether string functions are overloaded by their mbstring equivalents + */ + define('HTTP_REQUEST_MBSTRING', true); +} else { + /** + * @ignore + */ + define('HTTP_REQUEST_MBSTRING', false); +} + +/** + * Class for performing HTTP requests + * + * Simple example (fetches yahoo.com and displays it): + * <code> + * $a = &new HTTP_Request('http://www.yahoo.com/'); + * $a->sendRequest(); + * echo $a->getResponseBody(); + * </code> + * + * @category HTTP + * @package HTTP_Request + * @author Richard Heyes <richard@phpguru.org> + * @author Alexey Borzov <avb@php.net> + * @version Release: 1.4.2 + */ +class HTTP_Request +{ + /**#@+ + * @access private + */ + /** + * Instance of Net_URL + * @var Net_URL + */ + var $_url; + + /** + * Type of request + * @var string + */ + var $_method; + + /** + * HTTP Version + * @var string + */ + var $_http; + + /** + * Request headers + * @var array + */ + var $_requestHeaders; + + /** + * Basic Auth Username + * @var string + */ + var $_user; + + /** + * Basic Auth Password + * @var string + */ + var $_pass; + + /** + * Socket object + * @var Net_Socket + */ + var $_sock; + + /** + * Proxy server + * @var string + */ + var $_proxy_host; + + /** + * Proxy port + * @var integer + */ + var $_proxy_port; + + /** + * Proxy username + * @var string + */ + var $_proxy_user; + + /** + * Proxy password + * @var string + */ + var $_proxy_pass; + + /** + * Post data + * @var array + */ + var $_postData; + + /** + * Request body + * @var string + */ + var $_body; + + /** + * A list of methods that MUST NOT have a request body, per RFC 2616 + * @var array + */ + var $_bodyDisallowed = array('TRACE'); + + /** + * Files to post + * @var array + */ + var $_postFiles = array(); + + /** + * Connection timeout. + * @var float + */ + var $_timeout; + + /** + * HTTP_Response object + * @var HTTP_Response + */ + var $_response; + + /** + * Whether to allow redirects + * @var boolean + */ + var $_allowRedirects; + + /** + * Maximum redirects allowed + * @var integer + */ + var $_maxRedirects; + + /** + * Current number of redirects + * @var integer + */ + var $_redirects; + + /** + * Whether to append brackets [] to array variables + * @var bool + */ + var $_useBrackets = true; + + /** + * Attached listeners + * @var array + */ + var $_listeners = array(); + + /** + * Whether to save response body in response object property + * @var bool + */ + var $_saveBody = true; + + /** + * Timeout for reading from socket (array(seconds, microseconds)) + * @var array + */ + var $_readTimeout = null; + + /** + * Options to pass to Net_Socket::connect. See stream_context_create + * @var array + */ + var $_socketOptions = null; + /**#@-*/ + + /** + * Constructor + * + * Sets up the object + * @param string The url to fetch/access + * @param array Associative array of parameters which can have the following keys: + * <ul> + * <li>method - Method to use, GET, POST etc (string)</li> + * <li>http - HTTP Version to use, 1.0 or 1.1 (string)</li> + * <li>user - Basic Auth username (string)</li> + * <li>pass - Basic Auth password (string)</li> + * <li>proxy_host - Proxy server host (string)</li> + * <li>proxy_port - Proxy server port (integer)</li> + * <li>proxy_user - Proxy auth username (string)</li> + * <li>proxy_pass - Proxy auth password (string)</li> + * <li>timeout - Connection timeout in seconds (float)</li> + * <li>allowRedirects - Whether to follow redirects or not (bool)</li> + * <li>maxRedirects - Max number of redirects to follow (integer)</li> + * <li>useBrackets - Whether to append [] to array variable names (bool)</li> + * <li>saveBody - Whether to save response body in response object property (bool)</li> + * <li>readTimeout - Timeout for reading / writing data over the socket (array (seconds, microseconds))</li> + * <li>socketOptions - Options to pass to Net_Socket object (array)</li> + * </ul> + * @access public + */ + function HTTP_Request($url = '', $params = array()) + { + $this->_method = HTTP_REQUEST_METHOD_GET; + $this->_http = HTTP_REQUEST_HTTP_VER_1_1; + $this->_requestHeaders = array(); + $this->_postData = array(); + $this->_body = null; + + $this->_user = null; + $this->_pass = null; + + $this->_proxy_host = null; + $this->_proxy_port = null; + $this->_proxy_user = null; + $this->_proxy_pass = null; + + $this->_allowRedirects = false; + $this->_maxRedirects = 3; + $this->_redirects = 0; + + $this->_timeout = null; + $this->_response = null; + + foreach ($params as $key => $value) { + $this->{'_' . $key} = $value; + } + + if (!empty($url)) { + $this->setURL($url); + } + + // Default useragent + $this->addHeader('User-Agent', 'PEAR HTTP_Request class ( http://pear.php.net/ )'); + + // We don't do keep-alives by default + $this->addHeader('Connection', 'close'); + + // Basic authentication + if (!empty($this->_user)) { + $this->addHeader('Authorization', 'Basic ' . base64_encode($this->_user . ':' . $this->_pass)); + } + + // Proxy authentication (see bug #5913) + if (!empty($this->_proxy_user)) { + $this->addHeader('Proxy-Authorization', 'Basic ' . base64_encode($this->_proxy_user . ':' . $this->_proxy_pass)); + } + + // Use gzip encoding if possible + if (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && extension_loaded('zlib')) { + $this->addHeader('Accept-Encoding', 'gzip'); + } + } + + /** + * Generates a Host header for HTTP/1.1 requests + * + * @access private + * @return string + */ + function _generateHostHeader() + { + if ($this->_url->port != 80 AND strcasecmp($this->_url->protocol, 'http') == 0) { + $host = $this->_url->host . ':' . $this->_url->port; + + } elseif ($this->_url->port != 443 AND strcasecmp($this->_url->protocol, 'https') == 0) { + $host = $this->_url->host . ':' . $this->_url->port; + + } elseif ($this->_url->port == 443 AND strcasecmp($this->_url->protocol, 'https') == 0 AND strpos($this->_url->url, ':443') !== false) { + $host = $this->_url->host . ':' . $this->_url->port; + + } else { + $host = $this->_url->host; + } + + return $host; + } + + /** + * Resets the object to its initial state (DEPRECATED). + * Takes the same parameters as the constructor. + * + * @param string $url The url to be requested + * @param array $params Associative array of parameters + * (see constructor for details) + * @access public + * @deprecated deprecated since 1.2, call the constructor if this is necessary + */ + function reset($url, $params = array()) + { + $this->HTTP_Request($url, $params); + } + + /** + * Sets the URL to be requested + * + * @param string The url to be requested + * @access public + */ + function setURL($url) + { + $this->_url = &new Net_URL($url, $this->_useBrackets); + + if (!empty($this->_url->user) || !empty($this->_url->pass)) { + $this->setBasicAuth($this->_url->user, $this->_url->pass); + } + + if (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http) { + $this->addHeader('Host', $this->_generateHostHeader()); + } + + // set '/' instead of empty path rather than check later (see bug #8662) + if (empty($this->_url->path)) { + $this->_url->path = '/'; + } + } + + /** + * Returns the current request URL + * + * @return string Current request URL + * @access public + */ + function getUrl() + { + return empty($this->_url)? '': $this->_url->getUrl(); + } + + /** + * Sets a proxy to be used + * + * @param string Proxy host + * @param int Proxy port + * @param string Proxy username + * @param string Proxy password + * @access public + */ + function setProxy($host, $port = 8080, $user = null, $pass = null) + { + $this->_proxy_host = $host; + $this->_proxy_port = $port; + $this->_proxy_user = $user; + $this->_proxy_pass = $pass; + + if (!empty($user)) { + $this->addHeader('Proxy-Authorization', 'Basic ' . base64_encode($user . ':' . $pass)); + } + } + + /** + * Sets basic authentication parameters + * + * @param string Username + * @param string Password + */ + function setBasicAuth($user, $pass) + { + $this->_user = $user; + $this->_pass = $pass; + + $this->addHeader('Authorization', 'Basic ' . base64_encode($user . ':' . $pass)); + } + + /** + * Sets the method to be used, GET, POST etc. + * + * @param string Method to use. Use the defined constants for this + * @access public + */ + function setMethod($method) + { + $this->_method = $method; + } + + /** + * Sets the HTTP version to use, 1.0 or 1.1 + * + * @param string Version to use. Use the defined constants for this + * @access public + */ + function setHttpVer($http) + { + $this->_http = $http; + } + + /** + * Adds a request header + * + * @param string Header name + * @param string Header value + * @access public + */ + function addHeader($name, $value) + { + $this->_requestHeaders[strtolower($name)] = $value; + } + + /** + * Removes a request header + * + * @param string Header name to remove + * @access public + */ + function removeHeader($name) + { + if (isset($this->_requestHeaders[strtolower($name)])) { + unset($this->_requestHeaders[strtolower($name)]); + } + } + + /** + * Adds a querystring parameter + * + * @param string Querystring parameter name + * @param string Querystring parameter value + * @param bool Whether the value is already urlencoded or not, default = not + * @access public + */ + function addQueryString($name, $value, $preencoded = false) + { + $this->_url->addQueryString($name, $value, $preencoded); + } + + /** + * Sets the querystring to literally what you supply + * + * @param string The querystring data. Should be of the format foo=bar&x=y etc + * @param bool Whether data is already urlencoded or not, default = already encoded + * @access public + */ + function addRawQueryString($querystring, $preencoded = true) + { + $this->_url->addRawQueryString($querystring, $preencoded); + } + + /** + * Adds postdata items + * + * @param string Post data name + * @param string Post data value + * @param bool Whether data is already urlencoded or not, default = not + * @access public + */ + function addPostData($name, $value, $preencoded = false) + { + if ($preencoded) { + $this->_postData[$name] = $value; + } else { + $this->_postData[$name] = $this->_arrayMapRecursive('urlencode', $value); + } + } + + /** + * Recursively applies the callback function to the value + * + * @param mixed Callback function + * @param mixed Value to process + * @access private + * @return mixed Processed value + */ + function _arrayMapRecursive($callback, $value) + { + if (!is_array($value)) { + return call_user_func($callback, $value); + } else { + $map = array(); + foreach ($value as $k => $v) { + $map[$k] = $this->_arrayMapRecursive($callback, $v); + } + return $map; + } + } + + /** + * Adds a file to upload + * + * This also changes content-type to 'multipart/form-data' for proper upload + * + * @access public + * @param string name of file-upload field + * @param mixed file name(s) + * @param mixed content-type(s) of file(s) being uploaded + * @return bool true on success + * @throws PEAR_Error + */ + function addFile($inputName, $fileName, $contentType = 'application/octet-stream') + { + if (!is_array($fileName) && !is_readable($fileName)) { + return PEAR::raiseError("File '{$fileName}' is not readable", HTTP_REQUEST_ERROR_FILE); + } elseif (is_array($fileName)) { + foreach ($fileName as $name) { + if (!is_readable($name)) { + return PEAR::raiseError("File '{$name}' is not readable", HTTP_REQUEST_ERROR_FILE); + } + } + } + $this->addHeader('Content-Type', 'multipart/form-data'); + $this->_postFiles[$inputName] = array( + 'name' => $fileName, + 'type' => $contentType + ); + return true; + } + + /** + * Adds raw postdata (DEPRECATED) + * + * @param string The data + * @param bool Whether data is preencoded or not, default = already encoded + * @access public + * @deprecated deprecated since 1.3.0, method setBody() should be used instead + */ + function addRawPostData($postdata, $preencoded = true) + { + $this->_body = $preencoded ? $postdata : urlencode($postdata); + } + + /** + * Sets the request body (for POST, PUT and similar requests) + * + * @param string Request body + * @access public + */ + function setBody($body) + { + $this->_body = $body; + } + + /** + * Clears any postdata that has been added (DEPRECATED). + * + * Useful for multiple request scenarios. + * + * @access public + * @deprecated deprecated since 1.2 + */ + function clearPostData() + { + $this->_postData = null; + } + + /** + * Appends a cookie to "Cookie:" header + * + * @param string $name cookie name + * @param string $value cookie value + * @access public + */ + function addCookie($name, $value) + { + $cookies = isset($this->_requestHeaders['cookie']) ? $this->_requestHeaders['cookie']. '; ' : ''; + $this->addHeader('Cookie', $cookies . $name . '=' . $value); + } + + /** + * Clears any cookies that have been added (DEPRECATED). + * + * Useful for multiple request scenarios + * + * @access public + * @deprecated deprecated since 1.2 + */ + function clearCookies() + { + $this->removeHeader('Cookie'); + } + + /** + * Sends the request + * + * @access public + * @param bool Whether to store response body in Response object property, + * set this to false if downloading a LARGE file and using a Listener + * @return mixed PEAR error on error, true otherwise + */ + function sendRequest($saveBody = true) + { + if (!is_a($this->_url, 'Net_URL')) { + return PEAR::raiseError('No URL given', HTTP_REQUEST_ERROR_URL); + } + + $host = isset($this->_proxy_host) ? $this->_proxy_host : $this->_url->host; + $port = isset($this->_proxy_port) ? $this->_proxy_port : $this->_url->port; + + // 4.3.0 supports SSL connections using OpenSSL. The function test determines + // we running on at least 4.3.0 + if (strcasecmp($this->_url->protocol, 'https') == 0 AND function_exists('file_get_contents') AND extension_loaded('openssl')) { + if (isset($this->_proxy_host)) { + return PEAR::raiseError('HTTPS proxies are not supported', HTTP_REQUEST_ERROR_PROXY); + } + $host = 'ssl://' . $host; + } + + // magic quotes may fuck up file uploads and chunked response processing + $magicQuotes = ini_get('magic_quotes_runtime'); + ini_set('magic_quotes_runtime', false); + + // RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive + // connection token to a proxy server... + if (isset($this->_proxy_host) && !empty($this->_requestHeaders['connection']) && + 'Keep-Alive' == $this->_requestHeaders['connection']) + { + $this->removeHeader('connection'); + } + + $keepAlive = (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && empty($this->_requestHeaders['connection'])) || + (!empty($this->_requestHeaders['connection']) && 'Keep-Alive' == $this->_requestHeaders['connection']); + $sockets = &PEAR::getStaticProperty('HTTP_Request', 'sockets'); + $sockKey = $host . ':' . $port; + unset($this->_sock); + + // There is a connected socket in the "static" property? + if ($keepAlive && !empty($sockets[$sockKey]) && + !empty($sockets[$sockKey]->fp)) + { + $this->_sock =& $sockets[$sockKey]; + $err = null; + } else { + $this->_notify('connect'); + $this->_sock =& new Net_Socket(); + $err = $this->_sock->connect($host, $port, null, $this->_timeout, $this->_socketOptions); + } + PEAR::isError($err) or $err = $this->_sock->write($this->_buildRequest()); + + if (!PEAR::isError($err)) { + if (!empty($this->_readTimeout)) { + $this->_sock->setTimeout($this->_readTimeout[0], $this->_readTimeout[1]); + } + + $this->_notify('sentRequest'); + + // Read the response + $this->_response = &new HTTP_Response($this->_sock, $this->_listeners); + $err = $this->_response->process( + $this->_saveBody && $saveBody, + HTTP_REQUEST_METHOD_HEAD != $this->_method + ); + + if ($keepAlive) { + $keepAlive = (isset($this->_response->_headers['content-length']) + || (isset($this->_response->_headers['transfer-encoding']) + && strtolower($this->_response->_headers['transfer-encoding']) == 'chunked')); + if ($keepAlive) { + if (isset($this->_response->_headers['connection'])) { + $keepAlive = strtolower($this->_response->_headers['connection']) == 'keep-alive'; + } else { + $keepAlive = 'HTTP/'.HTTP_REQUEST_HTTP_VER_1_1 == $this->_response->_protocol; + } + } + } + } + + ini_set('magic_quotes_runtime', $magicQuotes); + + if (PEAR::isError($err)) { + return $err; + } + + if (!$keepAlive) { + $this->disconnect(); + // Store the connected socket in "static" property + } elseif (empty($sockets[$sockKey]) || empty($sockets[$sockKey]->fp)) { + $sockets[$sockKey] =& $this->_sock; + } + + // Check for redirection + if ( $this->_allowRedirects + AND $this->_redirects <= $this->_maxRedirects + AND $this->getResponseCode() > 300 + AND $this->getResponseCode() < 399 + AND !empty($this->_response->_headers['location'])) { + + + $redirect = $this->_response->_headers['location']; + + // Absolute URL + if (preg_match('/^https?:\/\//i', $redirect)) { + $this->_url = &new Net_URL($redirect); + $this->addHeader('Host', $this->_generateHostHeader()); + // Absolute path + } elseif ($redirect{0} == '/') { + $this->_url->path = $redirect; + + // Relative path + } elseif (substr($redirect, 0, 3) == '../' OR substr($redirect, 0, 2) == './') { + if (substr($this->_url->path, -1) == '/') { + $redirect = $this->_url->path . $redirect; + } else { + $redirect = dirname($this->_url->path) . '/' . $redirect; + } + $redirect = Net_URL::resolvePath($redirect); + $this->_url->path = $redirect; + + // Filename, no path + } else { + if (substr($this->_url->path, -1) == '/') { + $redirect = $this->_url->path . $redirect; + } else { + $redirect = dirname($this->_url->path) . '/' . $redirect; + } + $this->_url->path = $redirect; + } + + $this->_redirects++; + return $this->sendRequest($saveBody); + + // Too many redirects + } elseif ($this->_allowRedirects AND $this->_redirects > $this->_maxRedirects) { + return PEAR::raiseError('Too many redirects', HTTP_REQUEST_ERROR_REDIRECTS); + } + + return true; + } + + /** + * Disconnect the socket, if connected. Only useful if using Keep-Alive. + * + * @access public + */ + function disconnect() + { + if (!empty($this->_sock) && !empty($this->_sock->fp)) { + $this->_notify('disconnect'); + $this->_sock->disconnect(); + } + } + + /** + * Returns the response code + * + * @access public + * @return mixed Response code, false if not set + */ + function getResponseCode() + { + return isset($this->_response->_code) ? $this->_response->_code : false; + } + + /** + * Returns either the named header or all if no name given + * + * @access public + * @param string The header name to return, do not set to get all headers + * @return mixed either the value of $headername (false if header is not present) + * or an array of all headers + */ + function getResponseHeader($headername = null) + { + if (!isset($headername)) { + return isset($this->_response->_headers)? $this->_response->_headers: array(); + } else { + $headername = strtolower($headername); + return isset($this->_response->_headers[$headername]) ? $this->_response->_headers[$headername] : false; + } + } + + /** + * Returns the body of the response + * + * @access public + * @return mixed response body, false if not set + */ + function getResponseBody() + { + return isset($this->_response->_body) ? $this->_response->_body : false; + } + + /** + * Returns cookies set in response + * + * @access public + * @return mixed array of response cookies, false if none are present + */ + function getResponseCookies() + { + return isset($this->_response->_cookies) ? $this->_response->_cookies : false; + } + + /** + * Builds the request string + * + * @access private + * @return string The request string + */ + function _buildRequest() + { + $separator = ini_get('arg_separator.output'); + ini_set('arg_separator.output', '&'); + $querystring = ($querystring = $this->_url->getQueryString()) ? '?' . $querystring : ''; + ini_set('arg_separator.output', $separator); + + $host = isset($this->_proxy_host) ? $this->_url->protocol . '://' . $this->_url->host : ''; + $port = (isset($this->_proxy_host) AND $this->_url->port != 80) ? ':' . $this->_url->port : ''; + $path = $this->_url->path . $querystring; + $url = $host . $port . $path; + + if (!strlen($url)) { + $url = '/'; + } + + $request = $this->_method . ' ' . $url . ' HTTP/' . $this->_http . "\r\n"; + + if (in_array($this->_method, $this->_bodyDisallowed) || + (0 == strlen($this->_body) && (HTTP_REQUEST_METHOD_POST != $this->_method || + (empty($this->_postData) && empty($this->_postFiles))))) + { + $this->removeHeader('Content-Type'); + } else { + if (empty($this->_requestHeaders['content-type'])) { + // Add default content-type + $this->addHeader('Content-Type', 'application/x-www-form-urlencoded'); + } elseif ('multipart/form-data' == $this->_requestHeaders['content-type']) { + $boundary = 'HTTP_Request_' . md5(uniqid('request') . microtime()); + $this->addHeader('Content-Type', 'multipart/form-data; boundary=' . $boundary); + } + } + + // Request Headers + if (!empty($this->_requestHeaders)) { + foreach ($this->_requestHeaders as $name => $value) { + $canonicalName = implode('-', array_map('ucfirst', explode('-', $name))); + $request .= $canonicalName . ': ' . $value . "\r\n"; + } + } + + // No post data or wrong method, so simply add a final CRLF + if (in_array($this->_method, $this->_bodyDisallowed) || + (HTTP_REQUEST_METHOD_POST != $this->_method && 0 == strlen($this->_body))) { + + $request .= "\r\n"; + + // Post data if it's an array + } elseif (HTTP_REQUEST_METHOD_POST == $this->_method && + (!empty($this->_postData) || !empty($this->_postFiles))) { + + // "normal" POST request + if (!isset($boundary)) { + $postdata = implode('&', array_map( + create_function('$a', 'return $a[0] . \'=\' . $a[1];'), + $this->_flattenArray('', $this->_postData) + )); + + // multipart request, probably with file uploads + } else { + $postdata = ''; + if (!empty($this->_postData)) { + $flatData = $this->_flattenArray('', $this->_postData); + foreach ($flatData as $item) { + $postdata .= '--' . $boundary . "\r\n"; + $postdata .= 'Content-Disposition: form-data; name="' . $item[0] . '"'; + $postdata .= "\r\n\r\n" . urldecode($item[1]) . "\r\n"; + } + } + foreach ($this->_postFiles as $name => $value) { + if (is_array($value['name'])) { + $varname = $name . ($this->_useBrackets? '[]': ''); + } else { + $varname = $name; + $value['name'] = array($value['name']); + } + foreach ($value['name'] as $key => $filename) { + $fp = fopen($filename, 'r'); + $data = fread($fp, filesize($filename)); + fclose($fp); + $basename = basename($filename); + $type = is_array($value['type'])? @$value['type'][$key]: $value['type']; + + $postdata .= '--' . $boundary . "\r\n"; + $postdata .= 'Content-Disposition: form-data; name="' . $varname . '"; filename="' . $basename . '"'; + $postdata .= "\r\nContent-Type: " . $type; + $postdata .= "\r\n\r\n" . $data . "\r\n"; + } + } + $postdata .= '--' . $boundary . "--\r\n"; + } + $request .= 'Content-Length: ' . + (HTTP_REQUEST_MBSTRING? mb_strlen($postdata, 'iso-8859-1'): strlen($postdata)) . + "\r\n\r\n"; + $request .= $postdata; + + // Explicitly set request body + } elseif (0 < strlen($this->_body)) { + + $request .= 'Content-Length: ' . + (HTTP_REQUEST_MBSTRING? mb_strlen($this->_body, 'iso-8859-1'): strlen($this->_body)) . + "\r\n\r\n"; + $request .= $this->_body; + + // Terminate headers with CRLF on POST request with no body, too + } else { + + $request .= "\r\n"; + } + + return $request; + } + + /** + * Helper function to change the (probably multidimensional) associative array + * into the simple one. + * + * @param string name for item + * @param mixed item's values + * @return array array with the following items: array('item name', 'item value'); + * @access private + */ + function _flattenArray($name, $values) + { + if (!is_array($values)) { + return array(array($name, $values)); + } else { + $ret = array(); + foreach ($values as $k => $v) { + if (empty($name)) { + $newName = $k; + } elseif ($this->_useBrackets) { + $newName = $name . '[' . $k . ']'; + } else { + $newName = $name; + } + $ret = array_merge($ret, $this->_flattenArray($newName, $v)); + } + return $ret; + } + } + + + /** + * Adds a Listener to the list of listeners that are notified of + * the object's events + * + * Events sent by HTTP_Request object + * - 'connect': on connection to server + * - 'sentRequest': after the request was sent + * - 'disconnect': on disconnection from server + * + * Events sent by HTTP_Response object + * - 'gotHeaders': after receiving response headers (headers are passed in $data) + * - 'tick': on receiving a part of response body (the part is passed in $data) + * - 'gzTick': on receiving a gzip-encoded part of response body (ditto) + * - 'gotBody': after receiving the response body (passes the decoded body in $data if it was gzipped) + * + * @param HTTP_Request_Listener listener to attach + * @return boolean whether the listener was successfully attached + * @access public + */ + function attach(&$listener) + { + if (!is_a($listener, 'HTTP_Request_Listener')) { + return false; + } + $this->_listeners[$listener->getId()] =& $listener; + return true; + } + + + /** + * Removes a Listener from the list of listeners + * + * @param HTTP_Request_Listener listener to detach + * @return boolean whether the listener was successfully detached + * @access public + */ + function detach(&$listener) + { + if (!is_a($listener, 'HTTP_Request_Listener') || + !isset($this->_listeners[$listener->getId()])) { + return false; + } + unset($this->_listeners[$listener->getId()]); + return true; + } + + + /** + * Notifies all registered listeners of an event. + * + * @param string Event name + * @param mixed Additional data + * @access private + * @see HTTP_Request::attach() + */ + function _notify($event, $data = null) + { + foreach (array_keys($this->_listeners) as $id) { + $this->_listeners[$id]->update($this, $event, $data); + } + } +} + + +/** + * Response class to complement the Request class + * + * @category HTTP + * @package HTTP_Request + * @author Richard Heyes <richard@phpguru.org> + * @author Alexey Borzov <avb@php.net> + * @version Release: 1.4.2 + */ +class HTTP_Response +{ + /** + * Socket object + * @var Net_Socket + */ + var $_sock; + + /** + * Protocol + * @var string + */ + var $_protocol; + + /** + * Return code + * @var string + */ + var $_code; + + /** + * Response headers + * @var array + */ + var $_headers; + + /** + * Cookies set in response + * @var array + */ + var $_cookies; + + /** + * Response body + * @var string + */ + var $_body = ''; + + /** + * Used by _readChunked(): remaining length of the current chunk + * @var string + */ + var $_chunkLength = 0; + + /** + * Attached listeners + * @var array + */ + var $_listeners = array(); + + /** + * Bytes left to read from message-body + * @var null|int + */ + var $_toRead; + + /** + * Constructor + * + * @param Net_Socket socket to read the response from + * @param array listeners attached to request + */ + function HTTP_Response(&$sock, &$listeners) + { + $this->_sock =& $sock; + $this->_listeners =& $listeners; + } + + + /** + * Processes a HTTP response + * + * This extracts response code, headers, cookies and decodes body if it + * was encoded in some way + * + * @access public + * @param bool Whether to store response body in object property, set + * this to false if downloading a LARGE file and using a Listener. + * This is assumed to be true if body is gzip-encoded. + * @param bool Whether the response can actually have a message-body. + * Will be set to false for HEAD requests. + * @throws PEAR_Error + * @return mixed true on success, PEAR_Error in case of malformed response + */ + function process($saveBody = true, $canHaveBody = true) + { + do { + $line = $this->_sock->readLine(); + if (sscanf($line, 'HTTP/%s %s', $http_version, $returncode) != 2) { + return PEAR::raiseError('Malformed response', HTTP_REQUEST_ERROR_RESPONSE); + } else { + $this->_protocol = 'HTTP/' . $http_version; + $this->_code = intval($returncode); + } + while ('' !== ($header = $this->_sock->readLine())) { + $this->_processHeader($header); + } + } while (100 == $this->_code); + + $this->_notify('gotHeaders', $this->_headers); + + // RFC 2616, section 4.4: + // 1. Any response message which "MUST NOT" include a message-body ... + // is always terminated by the first empty line after the header fields + // 3. ... If a message is received with both a + // Transfer-Encoding header field and a Content-Length header field, + // the latter MUST be ignored. + $canHaveBody = $canHaveBody && $this->_code >= 200 && + $this->_code != 204 && $this->_code != 304; + + // If response body is present, read it and decode + $chunked = isset($this->_headers['transfer-encoding']) && ('chunked' == $this->_headers['transfer-encoding']); + $gzipped = isset($this->_headers['content-encoding']) && ('gzip' == $this->_headers['content-encoding']); + $hasBody = false; + if ($canHaveBody && ($chunked || !isset($this->_headers['content-length']) || + 0 != $this->_headers['content-length'])) + { + if ($chunked || !isset($this->_headers['content-length'])) { + $this->_toRead = null; + } else { + $this->_toRead = $this->_headers['content-length']; + } + while (!$this->_sock->eof() && (is_null($this->_toRead) || 0 < $this->_toRead)) { + if ($chunked) { + $data = $this->_readChunked(); + } elseif (is_null($this->_toRead)) { + $data = $this->_sock->read(4096); + } else { + $data = $this->_sock->read(min(4096, $this->_toRead)); + $this->_toRead -= HTTP_REQUEST_MBSTRING? mb_strlen($data, 'iso-8859-1'): strlen($data); + } + if ('' == $data) { + break; + } else { + $hasBody = true; + if ($saveBody || $gzipped) { + $this->_body .= $data; + } + $this->_notify($gzipped? 'gzTick': 'tick', $data); + } + } + } + + if ($hasBody) { + // Uncompress the body if needed + if ($gzipped) { + $body = $this->_decodeGzip($this->_body); + if (PEAR::isError($body)) { + return $body; + } + $this->_body = $body; + $this->_notify('gotBody', $this->_body); + } else { + $this->_notify('gotBody'); + } + } + return true; + } + + + /** + * Processes the response header + * + * @access private + * @param string HTTP header + */ + function _processHeader($header) + { + if (false === strpos($header, ':')) { + return; + } + list($headername, $headervalue) = explode(':', $header, 2); + $headername = strtolower($headername); + $headervalue = ltrim($headervalue); + + if ('set-cookie' != $headername) { + if (isset($this->_headers[$headername])) { + $this->_headers[$headername] .= ',' . $headervalue; + } else { + $this->_headers[$headername] = $headervalue; + } + } else { + $this->_parseCookie($headervalue); + } + } + + + /** + * Parse a Set-Cookie header to fill $_cookies array + * + * @access private + * @param string value of Set-Cookie header + */ + function _parseCookie($headervalue) + { + $cookie = array( + 'expires' => null, + 'domain' => null, + 'path' => null, + 'secure' => false + ); + + // Only a name=value pair + if (!strpos($headervalue, ';')) { + $pos = strpos($headervalue, '='); + $cookie['name'] = trim(substr($headervalue, 0, $pos)); + $cookie['value'] = trim(substr($headervalue, $pos + 1)); + + // Some optional parameters are supplied + } else { + $elements = explode(';', $headervalue); + $pos = strpos($elements[0], '='); + $cookie['name'] = trim(substr($elements[0], 0, $pos)); + $cookie['value'] = trim(substr($elements[0], $pos + 1)); + + for ($i = 1; $i < count($elements); $i++) { + if (false === strpos($elements[$i], '=')) { + $elName = trim($elements[$i]); + $elValue = null; + } else { + list ($elName, $elValue) = array_map('trim', explode('=', $elements[$i])); + } + $elName = strtolower($elName); + if ('secure' == $elName) { + $cookie['secure'] = true; + } elseif ('expires' == $elName) { + $cookie['expires'] = str_replace('"', '', $elValue); + } elseif ('path' == $elName || 'domain' == $elName) { + $cookie[$elName] = urldecode($elValue); + } else { + $cookie[$elName] = $elValue; + } + } + } + $this->_cookies[] = $cookie; + } + + + /** + * Read a part of response body encoded with chunked Transfer-Encoding + * + * @access private + * @return string + */ + function _readChunked() + { + // at start of the next chunk? + if (0 == $this->_chunkLength) { + $line = $this->_sock->readLine(); + if (preg_match('/^([0-9a-f]+)/i', $line, $matches)) { + $this->_chunkLength = hexdec($matches[1]); + // Chunk with zero length indicates the end + if (0 == $this->_chunkLength) { + $this->_sock->readLine(); // make this an eof() + return ''; + } + } else { + return ''; + } + } + $data = $this->_sock->read($this->_chunkLength); + $this->_chunkLength -= HTTP_REQUEST_MBSTRING? mb_strlen($data, 'iso-8859-1'): strlen($data); + if (0 == $this->_chunkLength) { + $this->_sock->readLine(); // Trailing CRLF + } + return $data; + } + + + /** + * Notifies all registered listeners of an event. + * + * @param string Event name + * @param mixed Additional data + * @access private + * @see HTTP_Request::_notify() + */ + function _notify($event, $data = null) + { + foreach (array_keys($this->_listeners) as $id) { + $this->_listeners[$id]->update($this, $event, $data); + } + } + + + /** + * Decodes the message-body encoded by gzip + * + * The real decoding work is done by gzinflate() built-in function, this + * method only parses the header and checks data for compliance with + * RFC 1952 + * + * @access private + * @param string gzip-encoded data + * @return string decoded data + */ + function _decodeGzip($data) + { + if (HTTP_REQUEST_MBSTRING) { + $oldEncoding = mb_internal_encoding(); + mb_internal_encoding('iso-8859-1'); + } + $length = strlen($data); + // If it doesn't look like gzip-encoded data, don't bother + if (18 > $length || strcmp(substr($data, 0, 2), "\x1f\x8b")) { + return $data; + } + $method = ord(substr($data, 2, 1)); + if (8 != $method) { + return PEAR::raiseError('_decodeGzip(): unknown compression method', HTTP_REQUEST_ERROR_GZIP_METHOD); + } + $flags = ord(substr($data, 3, 1)); + if ($flags & 224) { + return PEAR::raiseError('_decodeGzip(): reserved bits are set', HTTP_REQUEST_ERROR_GZIP_DATA); + } + + // header is 10 bytes minimum. may be longer, though. + $headerLength = 10; + // extra fields, need to skip 'em + if ($flags & 4) { + if ($length - $headerLength - 2 < 8) { + return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); + } + $extraLength = unpack('v', substr($data, 10, 2)); + if ($length - $headerLength - 2 - $extraLength[1] < 8) { + return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); + } + $headerLength += $extraLength[1] + 2; + } + // file name, need to skip that + if ($flags & 8) { + if ($length - $headerLength - 1 < 8) { + return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); + } + $filenameLength = strpos(substr($data, $headerLength), chr(0)); + if (false === $filenameLength || $length - $headerLength - $filenameLength - 1 < 8) { + return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); + } + $headerLength += $filenameLength + 1; + } + // comment, need to skip that also + if ($flags & 16) { + if ($length - $headerLength - 1 < 8) { + return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); + } + $commentLength = strpos(substr($data, $headerLength), chr(0)); + if (false === $commentLength || $length - $headerLength - $commentLength - 1 < 8) { + return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); + } + $headerLength += $commentLength + 1; + } + // have a CRC for header. let's check + if ($flags & 1) { + if ($length - $headerLength - 2 < 8) { + return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA); + } + $crcReal = 0xffff & crc32(substr($data, 0, $headerLength)); + $crcStored = unpack('v', substr($data, $headerLength, 2)); + if ($crcReal != $crcStored[1]) { + return PEAR::raiseError('_decodeGzip(): header CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC); + } + $headerLength += 2; + } + // unpacked data CRC and size at the end of encoded data + $tmp = unpack('V2', substr($data, -8)); + $dataCrc = $tmp[1]; + $dataSize = $tmp[2]; + + // finally, call the gzinflate() function + $unpacked = @gzinflate(substr($data, $headerLength, -8), $dataSize); + if (false === $unpacked) { + return PEAR::raiseError('_decodeGzip(): gzinflate() call failed', HTTP_REQUEST_ERROR_GZIP_READ); + } elseif ($dataSize != strlen($unpacked)) { + return PEAR::raiseError('_decodeGzip(): data size check failed', HTTP_REQUEST_ERROR_GZIP_READ); + } elseif ((0xffffffff & $dataCrc) != (0xffffffff & crc32($unpacked))) { + return PEAR::raiseError('_decodeGzip(): data CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC); + } + if (HTTP_REQUEST_MBSTRING) { + mb_internal_encoding($oldEncoding); + } + return $unpacked; + } +} // End class HTTP_Response +?> diff --git a/plugins/tidypics/lib/phpFlickr/PEAR/HTTP/Request/Listener.php b/plugins/tidypics/lib/phpFlickr/PEAR/HTTP/Request/Listener.php new file mode 100644 index 0000000000000000000000000000000000000000..b00514206ed9fca1baca9f84ef276d170d533601 --- /dev/null +++ b/plugins/tidypics/lib/phpFlickr/PEAR/HTTP/Request/Listener.php @@ -0,0 +1,106 @@ +<?php +/** + * Listener for HTTP_Request and HTTP_Response objects + * + * PHP versions 4 and 5 + * + * LICENSE: + * + * Copyright (c) 2002-2007, Richard Heyes + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * o Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * o Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * o The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @category HTTP + * @package HTTP_Request + * @author Alexey Borzov <avb@php.net> + * @copyright 2002-2007 Richard Heyes + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Listener.php 127 2008-01-17 20:21:37Z dcoulter $ + * @link http://pear.php.net/package/HTTP_Request/ + */ + +/** + * Listener for HTTP_Request and HTTP_Response objects + * + * This class implements the Observer part of a Subject-Observer + * design pattern. + * + * @category HTTP + * @package HTTP_Request + * @author Alexey Borzov <avb@php.net> + * @version Release: 1.4.2 + */ +class HTTP_Request_Listener +{ + /** + * A listener's identifier + * @var string + */ + var $_id; + + /** + * Constructor, sets the object's identifier + * + * @access public + */ + function HTTP_Request_Listener() + { + $this->_id = md5(uniqid('http_request_', 1)); + } + + + /** + * Returns the listener's identifier + * + * @access public + * @return string + */ + function getId() + { + return $this->_id; + } + + + /** + * This method is called when Listener is notified of an event + * + * @access public + * @param object an object the listener is attached to + * @param string Event name + * @param mixed Additional data + * @abstract + */ + function update(&$subject, $event, $data = null) + { + echo "Notified of event: '$event'\n"; + if (null !== $data) { + echo "Additional data: "; + var_dump($data); + } + } +} +?> diff --git a/plugins/tidypics/lib/phpFlickr/PEAR/Net/Socket.php b/plugins/tidypics/lib/phpFlickr/PEAR/Net/Socket.php new file mode 100644 index 0000000000000000000000000000000000000000..96f2c4bf140c6ddabc120c67e7d75a58e3f9f6a8 --- /dev/null +++ b/plugins/tidypics/lib/phpFlickr/PEAR/Net/Socket.php @@ -0,0 +1,528 @@ +<?php +// +// +----------------------------------------------------------------------+ +// | PHP Version 4 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1997-2003 The PHP Group | +// +----------------------------------------------------------------------+ +// | This source file is subject to version 2.0 of the PHP license, | +// | that is bundled with this package in the file LICENSE, and is | +// | available at through the world-wide-web at | +// | http://www.php.net/license/2_02.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +----------------------------------------------------------------------+ +// | Authors: Stig Bakken <ssb@php.net> | +// | Chuck Hagenbuch <chuck@horde.org> | +// +----------------------------------------------------------------------+ +// +// $Id: Socket.php 32 2005-08-01 06:21:02Z dancoulter $ + +require_once 'PEAR.php'; + +define('NET_SOCKET_READ', 1); +define('NET_SOCKET_WRITE', 2); +define('NET_SOCKET_ERROR', 3); + +/** + * Generalized Socket class. + * + * @version 1.1 + * @author Stig Bakken <ssb@php.net> + * @author Chuck Hagenbuch <chuck@horde.org> + */ +class Net_Socket extends PEAR { + + /** + * Socket file pointer. + * @var resource $fp + */ + var $fp = null; + + /** + * Whether the socket is blocking. Defaults to true. + * @var boolean $blocking + */ + var $blocking = true; + + /** + * Whether the socket is persistent. Defaults to false. + * @var boolean $persistent + */ + var $persistent = false; + + /** + * The IP address to connect to. + * @var string $addr + */ + var $addr = ''; + + /** + * The port number to connect to. + * @var integer $port + */ + var $port = 0; + + /** + * Number of seconds to wait on socket connections before assuming + * there's no more data. Defaults to no timeout. + * @var integer $timeout + */ + var $timeout = false; + + /** + * Number of bytes to read at a time in readLine() and + * readAll(). Defaults to 2048. + * @var integer $lineLength + */ + var $lineLength = 2048; + + /** + * Connect to the specified port. If called when the socket is + * already connected, it disconnects and connects again. + * + * @param string $addr IP address or host name. + * @param integer $port TCP port number. + * @param boolean $persistent (optional) Whether the connection is + * persistent (kept open between requests + * by the web server). + * @param integer $timeout (optional) How long to wait for data. + * @param array $options See options for stream_context_create. + * + * @access public + * + * @return boolean | PEAR_Error True on success or a PEAR_Error on failure. + */ + function connect($addr, $port = 0, $persistent = null, $timeout = null, $options = null) + { + if (is_resource($this->fp)) { + @fclose($this->fp); + $this->fp = null; + } + + if (!$addr) { + return $this->raiseError('$addr cannot be empty'); + } elseif (strspn($addr, '.0123456789') == strlen($addr) || + strstr($addr, '/') !== false) { + $this->addr = $addr; + } else { + $this->addr = @gethostbyname($addr); + } + + $this->port = $port % 65536; + + if ($persistent !== null) { + $this->persistent = $persistent; + } + + if ($timeout !== null) { + $this->timeout = $timeout; + } + + $openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen'; + $errno = 0; + $errstr = ''; + if ($options && function_exists('stream_context_create')) { + if ($this->timeout) { + $timeout = $this->timeout; + } else { + $timeout = 0; + } + $context = stream_context_create($options); + $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context); + } else { + if ($this->timeout) { + $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $this->timeout); + } else { + $fp = @$openfunc($this->addr, $this->port, $errno, $errstr); + } + } + + if (!$fp) { + return $this->raiseError($errstr, $errno); + } + + $this->fp = $fp; + + return $this->setBlocking($this->blocking); + } + + /** + * Disconnects from the peer, closes the socket. + * + * @access public + * @return mixed true on success or an error object otherwise + */ + function disconnect() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + @fclose($this->fp); + $this->fp = null; + return true; + } + + /** + * Find out if the socket is in blocking mode. + * + * @access public + * @return boolean The current blocking mode. + */ + function isBlocking() + { + return $this->blocking; + } + + /** + * Sets whether the socket connection should be blocking or + * not. A read call to a non-blocking socket will return immediately + * if there is no data available, whereas it will block until there + * is data for blocking sockets. + * + * @param boolean $mode True for blocking sockets, false for nonblocking. + * @access public + * @return mixed true on success or an error object otherwise + */ + function setBlocking($mode) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $this->blocking = $mode; + socket_set_blocking($this->fp, $this->blocking); + return true; + } + + /** + * Sets the timeout value on socket descriptor, + * expressed in the sum of seconds and microseconds + * + * @param integer $seconds Seconds. + * @param integer $microseconds Microseconds. + * @access public + * @return mixed true on success or an error object otherwise + */ + function setTimeout($seconds, $microseconds) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return socket_set_timeout($this->fp, $seconds, $microseconds); + } + + /** + * Returns information about an existing socket resource. + * Currently returns four entries in the result array: + * + * <p> + * timed_out (bool) - The socket timed out waiting for data<br> + * blocked (bool) - The socket was blocked<br> + * eof (bool) - Indicates EOF event<br> + * unread_bytes (int) - Number of bytes left in the socket buffer<br> + * </p> + * + * @access public + * @return mixed Array containing information about existing socket resource or an error object otherwise + */ + function getStatus() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return socket_get_status($this->fp); + } + + /** + * Get a specified line of data + * + * @access public + * @return $size bytes of data from the socket, or a PEAR_Error if + * not connected. + */ + function gets($size) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return @fgets($this->fp, $size); + } + + /** + * Read a specified amount of data. This is guaranteed to return, + * and has the added benefit of getting everything in one fread() + * chunk; if you know the size of the data you're getting + * beforehand, this is definitely the way to go. + * + * @param integer $size The number of bytes to read from the socket. + * @access public + * @return $size bytes of data from the socket, or a PEAR_Error if + * not connected. + */ + function read($size) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return @fread($this->fp, $size); + } + + /** + * Write a specified amount of data. + * + * @param string $data Data to write. + * @param integer $blocksize Amount of data to write at once. + * NULL means all at once. + * + * @access public + * @return mixed true on success or an error object otherwise + */ + function write($data, $blocksize = null) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + if (is_null($blocksize) && !OS_WINDOWS) { + return fwrite($this->fp, $data); + } else { + if (is_null($blocksize)) { + $blocksize = 1024; + } + + $pos = 0; + $size = strlen($data); + while ($pos < $size) { + $written = @fwrite($this->fp, substr($data, $pos, $blocksize)); + if ($written === false) { + return false; + } + $pos += $written; + } + + return $pos; + } + } + + /** + * Write a line of data to the socket, followed by a trailing "\r\n". + * + * @access public + * @return mixed fputs result, or an error + */ + function writeLine($data) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return fwrite($this->fp, $data . "\r\n"); + } + + /** + * Tests for end-of-file on a socket descriptor. + * + * @access public + * @return bool + */ + function eof() + { + return (is_resource($this->fp) && feof($this->fp)); + } + + /** + * Reads a byte of data + * + * @access public + * @return 1 byte of data from the socket, or a PEAR_Error if + * not connected. + */ + function readByte() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + return ord(@fread($this->fp, 1)); + } + + /** + * Reads a word of data + * + * @access public + * @return 1 word of data from the socket, or a PEAR_Error if + * not connected. + */ + function readWord() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $buf = @fread($this->fp, 2); + return (ord($buf[0]) + (ord($buf[1]) << 8)); + } + + /** + * Reads an int of data + * + * @access public + * @return integer 1 int of data from the socket, or a PEAR_Error if + * not connected. + */ + function readInt() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $buf = @fread($this->fp, 4); + return (ord($buf[0]) + (ord($buf[1]) << 8) + + (ord($buf[2]) << 16) + (ord($buf[3]) << 24)); + } + + /** + * Reads a zero-terminated string of data + * + * @access public + * @return string, or a PEAR_Error if + * not connected. + */ + function readString() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $string = ''; + while (($char = @fread($this->fp, 1)) != "\x00") { + $string .= $char; + } + return $string; + } + + /** + * Reads an IP Address and returns it in a dot formated string + * + * @access public + * @return Dot formated string, or a PEAR_Error if + * not connected. + */ + function readIPAddress() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $buf = @fread($this->fp, 4); + return sprintf("%s.%s.%s.%s", ord($buf[0]), ord($buf[1]), + ord($buf[2]), ord($buf[3])); + } + + /** + * Read until either the end of the socket or a newline, whichever + * comes first. Strips the trailing newline from the returned data. + * + * @access public + * @return All available data up to a newline, without that + * newline, or until the end of the socket, or a PEAR_Error if + * not connected. + */ + function readLine() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $line = ''; + $timeout = time() + $this->timeout; + while (!feof($this->fp) && (!$this->timeout || time() < $timeout)) { + $line .= @fgets($this->fp, $this->lineLength); + if (substr($line, -1) == "\n") { + return rtrim($line, "\r\n"); + } + } + return $line; + } + + /** + * Read until the socket closes, or until there is no more data in + * the inner PHP buffer. If the inner buffer is empty, in blocking + * mode we wait for at least 1 byte of data. Therefore, in + * blocking mode, if there is no data at all to be read, this + * function will never exit (unless the socket is closed on the + * remote end). + * + * @access public + * + * @return string All data until the socket closes, or a PEAR_Error if + * not connected. + */ + function readAll() + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $data = ''; + while (!feof($this->fp)) { + $data .= @fread($this->fp, $this->lineLength); + } + return $data; + } + + /** + * Runs the equivalent of the select() system call on the socket + * with a timeout specified by tv_sec and tv_usec. + * + * @param integer $state Which of read/write/error to check for. + * @param integer $tv_sec Number of seconds for timeout. + * @param integer $tv_usec Number of microseconds for timeout. + * + * @access public + * @return False if select fails, integer describing which of read/write/error + * are ready, or PEAR_Error if not connected. + */ + function select($state, $tv_sec, $tv_usec = 0) + { + if (!is_resource($this->fp)) { + return $this->raiseError('not connected'); + } + + $read = null; + $write = null; + $except = null; + if ($state & NET_SOCKET_READ) { + $read[] = $this->fp; + } + if ($state & NET_SOCKET_WRITE) { + $write[] = $this->fp; + } + if ($state & NET_SOCKET_ERROR) { + $except[] = $this->fp; + } + if (false === ($sr = stream_select($read, $write, $except, $tv_sec, $tv_usec))) { + return false; + } + + $result = 0; + if (count($read)) { + $result |= NET_SOCKET_READ; + } + if (count($write)) { + $result |= NET_SOCKET_WRITE; + } + if (count($except)) { + $result |= NET_SOCKET_ERROR; + } + return $result; + } + +} diff --git a/plugins/tidypics/lib/phpFlickr/PEAR/Net/URL.php b/plugins/tidypics/lib/phpFlickr/PEAR/Net/URL.php new file mode 100644 index 0000000000000000000000000000000000000000..38e26fd15715131c1bda1ba3e934408c270694fb --- /dev/null +++ b/plugins/tidypics/lib/phpFlickr/PEAR/Net/URL.php @@ -0,0 +1,410 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Copyright (c) 2002-2004, Richard Heyes | +// | All rights reserved. | +// | | +// | Redistribution and use in source and binary forms, with or without | +// | modification, are permitted provided that the following conditions | +// | are met: | +// | | +// | o Redistributions of source code must retain the above copyright | +// | notice, this list of conditions and the following disclaimer. | +// | o Redistributions in binary form must reproduce the above copyright | +// | notice, this list of conditions and the following disclaimer in the | +// | documentation and/or other materials provided with the distribution.| +// | o The names of the authors may not be used to endorse or promote | +// | products derived from this software without specific prior written | +// | permission. | +// | | +// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | +// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | +// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | +// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | +// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | +// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | +// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | +// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | +// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | +// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | +// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | +// | | +// +-----------------------------------------------------------------------+ +// | Author: Richard Heyes <richard at php net> | +// +-----------------------------------------------------------------------+ +// +// $Id: URL.php 32 2005-08-01 06:21:02Z dancoulter $ +// +// Net_URL Class + +class Net_URL +{ + /** + * Full url + * @var string + */ + var $url; + + /** + * Protocol + * @var string + */ + var $protocol; + + /** + * Username + * @var string + */ + var $username; + + /** + * Password + * @var string + */ + var $password; + + /** + * Host + * @var string + */ + var $host; + + /** + * Port + * @var integer + */ + var $port; + + /** + * Path + * @var string + */ + var $path; + + /** + * Query string + * @var array + */ + var $querystring; + + /** + * Anchor + * @var string + */ + var $anchor; + + /** + * Whether to use [] + * @var bool + */ + var $useBrackets; + + /** + * PHP4 Constructor + * + * @see __construct() + */ + function Net_URL($url = null, $useBrackets = true) + { + $this->__construct($url, $useBrackets); + } + + /** + * PHP5 Constructor + * + * Parses the given url and stores the various parts + * Defaults are used in certain cases + * + * @param string $url Optional URL + * @param bool $useBrackets Whether to use square brackets when + * multiple querystrings with the same name + * exist + */ + function __construct($url = null, $useBrackets = true) + { + $HTTP_SERVER_VARS = !empty($_SERVER) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; + + $this->useBrackets = $useBrackets; + $this->url = $url; + $this->user = ''; + $this->pass = ''; + $this->host = ''; + $this->port = 80; + $this->path = ''; + $this->querystring = array(); + $this->anchor = ''; + + // Only use defaults if not an absolute URL given + if (!preg_match('/^[a-z0-9]+:\/\//i', $url)) { + + $this->protocol = (@$HTTP_SERVER_VARS['HTTPS'] == 'on' ? 'https' : 'http'); + + /** + * Figure out host/port + */ + if (!empty($HTTP_SERVER_VARS['HTTP_HOST']) AND preg_match('/^(.*)(:([0-9]+))?$/U', $HTTP_SERVER_VARS['HTTP_HOST'], $matches)) { + $host = $matches[1]; + if (!empty($matches[3])) { + $port = $matches[3]; + } else { + $port = $this->getStandardPort($this->protocol); + } + } + + $this->user = ''; + $this->pass = ''; + $this->host = !empty($host) ? $host : (isset($HTTP_SERVER_VARS['SERVER_NAME']) ? $HTTP_SERVER_VARS['SERVER_NAME'] : 'localhost'); + $this->port = !empty($port) ? $port : (isset($HTTP_SERVER_VARS['SERVER_PORT']) ? $HTTP_SERVER_VARS['SERVER_PORT'] : $this->getStandardPort($this->protocol)); + $this->path = !empty($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : '/'; + $this->querystring = isset($HTTP_SERVER_VARS['QUERY_STRING']) ? $this->_parseRawQuerystring($HTTP_SERVER_VARS['QUERY_STRING']) : null; + $this->anchor = ''; + } + + // Parse the url and store the various parts + if (!empty($url)) { + $urlinfo = parse_url($url); + + // Default querystring + $this->querystring = array(); + + foreach ($urlinfo as $key => $value) { + switch ($key) { + case 'scheme': + $this->protocol = $value; + $this->port = $this->getStandardPort($value); + break; + + case 'user': + case 'pass': + case 'host': + case 'port': + $this->$key = $value; + break; + + case 'path': + if ($value{0} == '/') { + $this->path = $value; + } else { + $path = dirname($this->path) == DIRECTORY_SEPARATOR ? '' : dirname($this->path); + $this->path = sprintf('%s/%s', $path, $value); + } + break; + + case 'query': + $this->querystring = $this->_parseRawQueryString($value); + break; + + case 'fragment': + $this->anchor = $value; + break; + } + } + } + } + + /** + * Returns full url + * + * @return string Full url + * @access public + */ + function getURL() + { + $querystring = $this->getQueryString(); + + $this->url = $this->protocol . '://' + . $this->user . (!empty($this->pass) ? ':' : '') + . $this->pass . (!empty($this->user) ? '@' : '') + . $this->host . ($this->port == $this->getStandardPort($this->protocol) ? '' : ':' . $this->port) + . $this->path + . (!empty($querystring) ? '?' . $querystring : '') + . (!empty($this->anchor) ? '#' . $this->anchor : ''); + + return $this->url; + } + + /** + * Adds a querystring item + * + * @param string $name Name of item + * @param string $value Value of item + * @param bool $preencoded Whether value is urlencoded or not, default = not + * @access public + */ + function addQueryString($name, $value, $preencoded = false) + { + if ($preencoded) { + $this->querystring[$name] = $value; + } else { + $this->querystring[$name] = is_array($value) ? array_map('rawurlencode', $value): rawurlencode($value); + } + } + + /** + * Removes a querystring item + * + * @param string $name Name of item + * @access public + */ + function removeQueryString($name) + { + if (isset($this->querystring[$name])) { + unset($this->querystring[$name]); + } + } + + /** + * Sets the querystring to literally what you supply + * + * @param string $querystring The querystring data. Should be of the format foo=bar&x=y etc + * @access public + */ + function addRawQueryString($querystring) + { + $this->querystring = $this->_parseRawQueryString($querystring); + } + + /** + * Returns flat querystring + * + * @return string Querystring + * @access public + */ + function getQueryString() + { + if (!empty($this->querystring)) { + foreach ($this->querystring as $name => $value) { + if (is_array($value)) { + foreach ($value as $k => $v) { + $querystring[] = $this->useBrackets ? sprintf('%s[%s]=%s', $name, $k, $v) : ($name . '=' . $v); + } + } elseif (!is_null($value)) { + $querystring[] = $name . '=' . $value; + } else { + $querystring[] = $name; + } + } + $querystring = implode(ini_get('arg_separator.output'), $querystring); + } else { + $querystring = ''; + } + + return $querystring; + } + + /** + * Parses raw querystring and returns an array of it + * + * @param string $querystring The querystring to parse + * @return array An array of the querystring data + * @access private + */ + function _parseRawQuerystring($querystring) + { + $parts = preg_split('/[' . preg_quote(ini_get('arg_separator.input'), '/') . ']/', $querystring, -1, PREG_SPLIT_NO_EMPTY); + $return = array(); + + foreach ($parts as $part) { + if (strpos($part, '=') !== false) { + $value = substr($part, strpos($part, '=') + 1); + $key = substr($part, 0, strpos($part, '=')); + } else { + $value = null; + $key = $part; + } + if (substr($key, -2) == '[]') { + $key = substr($key, 0, -2); + if (@!is_array($return[$key])) { + $return[$key] = array(); + $return[$key][] = $value; + } else { + $return[$key][] = $value; + } + } elseif (!$this->useBrackets AND !empty($return[$key])) { + $return[$key] = (array)$return[$key]; + $return[$key][] = $value; + } else { + $return[$key] = $value; + } + } + + return $return; + } + + /** + * Resolves //, ../ and ./ from a path and returns + * the result. Eg: + * + * /foo/bar/../boo.php => /foo/boo.php + * /foo/bar/../../boo.php => /boo.php + * /foo/bar/.././/boo.php => /foo/boo.php + * + * This method can also be called statically. + * + * @param string $url URL path to resolve + * @return string The result + */ + function resolvePath($path) + { + $path = explode('/', str_replace('//', '/', $path)); + + for ($i=0; $i<count($path); $i++) { + if ($path[$i] == '.') { + unset($path[$i]); + $path = array_values($path); + $i--; + + } elseif ($path[$i] == '..' AND ($i > 1 OR ($i == 1 AND $path[0] != '') ) ) { + unset($path[$i]); + unset($path[$i-1]); + $path = array_values($path); + $i -= 2; + + } elseif ($path[$i] == '..' AND $i == 1 AND $path[0] == '') { + unset($path[$i]); + $path = array_values($path); + $i--; + + } else { + continue; + } + } + + return implode('/', $path); + } + + /** + * Returns the standard port number for a protocol + * + * @param string $scheme The protocol to lookup + * @return integer Port number or NULL if no scheme matches + * + * @author Philippe Jausions <Philippe.Jausions@11abacus.com> + */ + function getStandardPort($scheme) + { + switch (strtolower($scheme)) { + case 'http': return 80; + case 'https': return 443; + case 'ftp': return 21; + case 'imap': return 143; + case 'imaps': return 993; + case 'pop3': return 110; + case 'pop3s': return 995; + default: return null; + } + } + + /** + * Forces the URL to a particular protocol + * + * @param string $protocol Protocol to force the URL to + * @param integer $port Optional port (standard port is used by default) + */ + function setProtocol($protocol, $port = null) + { + $this->protocol = $protocol; + $this->port = is_null($port) ? $this->getStandardPort() : $port; + } + +} +?> diff --git a/plugins/tidypics/lib/phpFlickr/PEAR/PEAR.php b/plugins/tidypics/lib/phpFlickr/PEAR/PEAR.php new file mode 100644 index 0000000000000000000000000000000000000000..e442d8c7ac1c64304e0cbb986869390d3d4e253a --- /dev/null +++ b/plugins/tidypics/lib/phpFlickr/PEAR/PEAR.php @@ -0,0 +1,1108 @@ +<?php +/** + * PEAR, the PHP Extension and Application Repository + * + * PEAR class and PEAR_Error class + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Sterling Hughes <sterling@php.net> + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V.Cox <cox@idecnet.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2006 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: PEAR.php 127 2008-01-17 20:21:37Z dcoulter $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/**#@+ + * ERROR constants + */ +define('PEAR_ERROR_RETURN', 1); +define('PEAR_ERROR_PRINT', 2); +define('PEAR_ERROR_TRIGGER', 4); +define('PEAR_ERROR_DIE', 8); +define('PEAR_ERROR_CALLBACK', 16); +/** + * WARNING: obsolete + * @deprecated + */ +define('PEAR_ERROR_EXCEPTION', 32); +/**#@-*/ +define('PEAR_ZE2', (function_exists('version_compare') && + version_compare(zend_version(), "2-dev", "ge"))); + +if (substr(PHP_OS, 0, 3) == 'WIN') { + define('OS_WINDOWS', true); + define('OS_UNIX', false); + define('PEAR_OS', 'Windows'); +} else { + define('OS_WINDOWS', false); + define('OS_UNIX', true); + define('PEAR_OS', 'Unix'); // blatant assumption +} + +// instant backwards compatibility +if (!defined('PATH_SEPARATOR')) { + if (OS_WINDOWS) { + define('PATH_SEPARATOR', ';'); + } else { + define('PATH_SEPARATOR', ':'); + } +} + +$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; +$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; +$GLOBALS['_PEAR_destructor_object_list'] = array(); +$GLOBALS['_PEAR_shutdown_funcs'] = array(); +$GLOBALS['_PEAR_error_handler_stack'] = array(); + +@ini_set('track_errors', true); + +/** + * Base class for other PEAR classes. Provides rudimentary + * emulation of destructors. + * + * If you want a destructor in your class, inherit PEAR and make a + * destructor method called _yourclassname (same name as the + * constructor, but with a "_" prefix). Also, in your constructor you + * have to call the PEAR constructor: $this->PEAR();. + * The destructor method will be called without parameters. Note that + * at in some SAPI implementations (such as Apache), any output during + * the request shutdown (in which destructors are called) seems to be + * discarded. If you need to get any debug information from your + * destructor, use error_log(), syslog() or something similar. + * + * IMPORTANT! To use the emulated destructors you need to create the + * objects by reference: $obj =& new PEAR_child; + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V. Cox <cox@idecnet.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2006 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.6.2 + * @link http://pear.php.net/package/PEAR + * @see PEAR_Error + * @since Class available since PHP 4.0.2 + * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear + */ +class PEAR +{ + // {{{ properties + + /** + * Whether to enable internal debug messages. + * + * @var bool + * @access private + */ + var $_debug = false; + + /** + * Default error mode for this object. + * + * @var int + * @access private + */ + var $_default_error_mode = null; + + /** + * Default error options used for this object when error mode + * is PEAR_ERROR_TRIGGER. + * + * @var int + * @access private + */ + var $_default_error_options = null; + + /** + * Default error handler (callback) for this object, if error mode is + * PEAR_ERROR_CALLBACK. + * + * @var string + * @access private + */ + var $_default_error_handler = ''; + + /** + * Which class to use for error objects. + * + * @var string + * @access private + */ + var $_error_class = 'PEAR_Error'; + + /** + * An array of expected errors. + * + * @var array + * @access private + */ + var $_expected_errors = array(); + + // }}} + + // {{{ constructor + + /** + * Constructor. Registers this object in + * $_PEAR_destructor_object_list for destructor emulation if a + * destructor object exists. + * + * @param string $error_class (optional) which class to use for + * error objects, defaults to PEAR_Error. + * @access public + * @return void + */ + function PEAR($error_class = null) + { + $classname = strtolower(get_class($this)); + if ($this->_debug) { + print "PEAR constructor called, class=$classname\n"; + } + if ($error_class !== null) { + $this->_error_class = $error_class; + } + while ($classname && strcasecmp($classname, "pear")) { + $destructor = "_$classname"; + if (method_exists($this, $destructor)) { + global $_PEAR_destructor_object_list; + $_PEAR_destructor_object_list[] = &$this; + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + break; + } else { + $classname = get_parent_class($classname); + } + } + } + + // }}} + // {{{ destructor + + /** + * Destructor (the emulated type of...). Does nothing right now, + * but is included for forward compatibility, so subclass + * destructors should always call it. + * + * See the note in the class desciption about output from + * destructors. + * + * @access public + * @return void + */ + function _PEAR() { + if ($this->_debug) { + printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); + } + } + + // }}} + // {{{ getStaticProperty() + + /** + * If you have a class that's mostly/entirely static, and you need static + * properties, you can use this method to simulate them. Eg. in your method(s) + * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); + * You MUST use a reference, or they will not persist! + * + * @access public + * @param string $class The calling classname, to prevent clashes + * @param string $var The variable to retrieve. + * @return mixed A reference to the variable. If not set it will be + * auto initialised to NULL. + */ + function &getStaticProperty($class, $var) + { + static $properties; + if (!isset($properties[$class])) { + $properties[$class] = array(); + } + if (!array_key_exists($var, $properties[$class])) { + $properties[$class][$var] = null; + } + return $properties[$class][$var]; + } + + // }}} + // {{{ registerShutdownFunc() + + /** + * Use this function to register a shutdown method for static + * classes. + * + * @access public + * @param mixed $func The function name (or array of class/method) to call + * @param mixed $args The arguments to pass to the function + * @return void + */ + function registerShutdownFunc($func, $args = array()) + { + // if we are called statically, there is a potential + // that no shutdown func is registered. Bug #6445 + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); + } + + // }}} + // {{{ isError() + + /** + * Tell whether a value is a PEAR error. + * + * @param mixed $data the value to test + * @param int $code if $data is an error object, return true + * only if $code is a string and + * $obj->getMessage() == $code or + * $code is an integer and $obj->getCode() == $code + * @access public + * @return bool true if parameter is an error + */ + function isError($data, $code = null) + { + if (is_a($data, 'PEAR_Error')) { + if (is_null($code)) { + return true; + } elseif (is_string($code)) { + return $data->getMessage() == $code; + } else { + return $data->getCode() == $code; + } + } + return false; + } + + // }}} + // {{{ setErrorHandling() + + /** + * Sets how errors generated by this object should be handled. + * Can be invoked both in objects and statically. If called + * statically, setErrorHandling sets the default behaviour for all + * PEAR objects. If called in an object, setErrorHandling sets + * the default behaviour for that object. + * + * @param int $mode + * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. + * + * @param mixed $options + * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one + * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * + * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected + * to be the callback function or method. A callback + * function is a string with the name of the function, a + * callback method is an array of two elements: the element + * at index 0 is the object, and the element at index 1 is + * the name of the method to call in the object. + * + * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is + * a printf format string used when printing the error + * message. + * + * @access public + * @return void + * @see PEAR_ERROR_RETURN + * @see PEAR_ERROR_PRINT + * @see PEAR_ERROR_TRIGGER + * @see PEAR_ERROR_DIE + * @see PEAR_ERROR_CALLBACK + * @see PEAR_ERROR_EXCEPTION + * + * @since PHP 4.0.5 + */ + + function setErrorHandling($mode = null, $options = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + $setmode = &$this->_default_error_mode; + $setoptions = &$this->_default_error_options; + } else { + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + } + + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + } + + // }}} + // {{{ expectError() + + /** + * This method is used to tell which errors you expect to get. + * Expected errors are always returned with error mode + * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, + * and this method pushes a new element onto it. The list of + * expected errors are in effect until they are popped off the + * stack with the popExpect() method. + * + * Note that this method can not be called statically + * + * @param mixed $code a single error code or an array of error codes to expect + * + * @return int the new depth of the "expected errors" stack + * @access public + */ + function expectError($code = '*') + { + if (is_array($code)) { + array_push($this->_expected_errors, $code); + } else { + array_push($this->_expected_errors, array($code)); + } + return sizeof($this->_expected_errors); + } + + // }}} + // {{{ popExpect() + + /** + * This method pops one element off the expected error codes + * stack. + * + * @return array the list of error codes that were popped + */ + function popExpect() + { + return array_pop($this->_expected_errors); + } + + // }}} + // {{{ _checkDelExpect() + + /** + * This method checks unsets an error code if available + * + * @param mixed error code + * @return bool true if the error code was unset, false otherwise + * @access private + * @since PHP 4.3.0 + */ + function _checkDelExpect($error_code) + { + $deleted = false; + + foreach ($this->_expected_errors AS $key => $error_array) { + if (in_array($error_code, $error_array)) { + unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); + $deleted = true; + } + + // clean up empty arrays + if (0 == count($this->_expected_errors[$key])) { + unset($this->_expected_errors[$key]); + } + } + return $deleted; + } + + // }}} + // {{{ delExpect() + + /** + * This method deletes all occurences of the specified element from + * the expected error codes stack. + * + * @param mixed $error_code error code that should be deleted + * @return mixed list of error codes that were deleted or error + * @access public + * @since PHP 4.3.0 + */ + function delExpect($error_code) + { + $deleted = false; + + if ((is_array($error_code) && (0 != count($error_code)))) { + // $error_code is a non-empty array here; + // we walk through it trying to unset all + // values + foreach($error_code as $key => $error) { + if ($this->_checkDelExpect($error)) { + $deleted = true; + } else { + $deleted = false; + } + } + return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } elseif (!empty($error_code)) { + // $error_code comes alone, trying to unset it + if ($this->_checkDelExpect($error_code)) { + return true; + } else { + return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } + } else { + // $error_code is empty + return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME + } + } + + // }}} + // {{{ raiseError() + + /** + * This method is a wrapper that returns an instance of the + * configured error class with this object's default error + * handling applied. If the $mode and $options parameters are not + * specified, the object's defaults are used. + * + * @param mixed $message a text error message or a PEAR error object + * + * @param int $code a numeric error code (it is up to your class + * to define these if you want to use codes) + * + * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. + * + * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter + * specifies the PHP-internal error level (one of + * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * If $mode is PEAR_ERROR_CALLBACK, this + * parameter specifies the callback function or + * method. In other error modes this parameter + * is ignored. + * + * @param string $userinfo If you need to pass along for example debug + * information, this parameter is meant for that. + * + * @param string $error_class The returned error object will be + * instantiated from this class, if specified. + * + * @param bool $skipmsg If true, raiseError will only pass error codes, + * the error message parameter will be dropped. + * + * @access public + * @return object a PEAR error object + * @see PEAR::setErrorHandling + * @since PHP 4.0.5 + */ + function &raiseError($message = null, + $code = null, + $mode = null, + $options = null, + $userinfo = null, + $error_class = null, + $skipmsg = false) + { + // The error is yet a PEAR error object + if (is_object($message)) { + $code = $message->getCode(); + $userinfo = $message->getUserInfo(); + $error_class = $message->getType(); + $message->error_message_prefix = ''; + $message = $message->getMessage(); + } + + if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { + if ($exp[0] == "*" || + (is_int(reset($exp)) && in_array($code, $exp)) || + (is_string(reset($exp)) && in_array($message, $exp))) { + $mode = PEAR_ERROR_RETURN; + } + } + // No mode given, try global ones + if ($mode === null) { + // Class error handler + if (isset($this) && isset($this->_default_error_mode)) { + $mode = $this->_default_error_mode; + $options = $this->_default_error_options; + // Global error handler + } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { + $mode = $GLOBALS['_PEAR_default_error_mode']; + $options = $GLOBALS['_PEAR_default_error_options']; + } + } + + if ($error_class !== null) { + $ec = $error_class; + } elseif (isset($this) && isset($this->_error_class)) { + $ec = $this->_error_class; + } else { + $ec = 'PEAR_Error'; + } + if ($skipmsg) { + $a = &new $ec($code, $mode, $options, $userinfo); + return $a; + } else { + $a = &new $ec($message, $code, $mode, $options, $userinfo); + return $a; + } + } + + // }}} + // {{{ throwError() + + /** + * Simpler form of raiseError with fewer options. In most cases + * message, code and userinfo are enough. + * + * @param string $message + * + */ + function &throwError($message = null, + $code = null, + $userinfo = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + $a = &$this->raiseError($message, $code, null, null, $userinfo); + return $a; + } else { + $a = &PEAR::raiseError($message, $code, null, null, $userinfo); + return $a; + } + } + + // }}} + function staticPushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + $stack[] = array($def_mode, $def_options); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $def_mode = $mode; + $def_options = $options; + break; + + case PEAR_ERROR_CALLBACK: + $def_mode = $mode; + // class/object method callback + if (is_callable($options)) { + $def_options = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + $stack[] = array($mode, $options); + return true; + } + + function staticPopErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + return true; + } + + // {{{ pushErrorHandling() + + /** + * Push a new error handler on top of the error handler options stack. With this + * you can easily override the actual error handler for some code and restore + * it later with popErrorHandling. + * + * @param mixed $mode (same as setErrorHandling) + * @param mixed $options (same as setErrorHandling) + * + * @return bool Always true + * + * @see PEAR::setErrorHandling + */ + function pushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + if (isset($this) && is_a($this, 'PEAR')) { + $def_mode = &$this->_default_error_mode; + $def_options = &$this->_default_error_options; + } else { + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + } + $stack[] = array($def_mode, $def_options); + + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + $stack[] = array($mode, $options); + return true; + } + + // }}} + // {{{ popErrorHandling() + + /** + * Pop the last error handler used + * + * @return bool Always true + * + * @see PEAR::pushErrorHandling + */ + function popErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + return true; + } + + // }}} + // {{{ loadExtension() + + /** + * OS independant PHP extension load. Remember to take care + * on the correct extension name for case sensitive OSes. + * + * @param string $ext The extension name + * @return bool Success or not on the dl() call + */ + function loadExtension($ext) + { + if (!extension_loaded($ext)) { + // if either returns true dl() will produce a FATAL error, stop that + if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { + return false; + } + if (OS_WINDOWS) { + $suffix = '.dll'; + } elseif (PHP_OS == 'HP-UX') { + $suffix = '.sl'; + } elseif (PHP_OS == 'AIX') { + $suffix = '.a'; + } elseif (PHP_OS == 'OSX') { + $suffix = '.bundle'; + } else { + $suffix = '.so'; + } + return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); + } + return true; + } + + // }}} +} + +// {{{ _PEAR_call_destructors() + +function _PEAR_call_destructors() +{ + global $_PEAR_destructor_object_list; + if (is_array($_PEAR_destructor_object_list) && + sizeof($_PEAR_destructor_object_list)) + { + reset($_PEAR_destructor_object_list); + if (PEAR::getStaticProperty('PEAR', 'destructlifo')) { + $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); + } + while (list($k, $objref) = each($_PEAR_destructor_object_list)) { + $classname = get_class($objref); + while ($classname) { + $destructor = "_$classname"; + if (method_exists($objref, $destructor)) { + $objref->$destructor(); + break; + } else { + $classname = get_parent_class($classname); + } + } + } + // Empty the object list to ensure that destructors are + // not called more than once. + $_PEAR_destructor_object_list = array(); + } + + // Now call the shutdown functions + if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { + foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { + call_user_func_array($value[0], $value[1]); + } + } +} + +// }}} +/** + * Standard PEAR error class for PHP 4 + * + * This class is supserseded by {@link PEAR_Exception} in PHP 5 + * + * @category pear + * @package PEAR + * @author Stig Bakken <ssb@php.net> + * @author Tomas V.V. Cox <cox@idecnet.com> + * @author Gregory Beaver <cellog@php.net> + * @copyright 1997-2006 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.6.2 + * @link http://pear.php.net/manual/en/core.pear.pear-error.php + * @see PEAR::raiseError(), PEAR::throwError() + * @since Class available since PHP 4.0.2 + */ +class PEAR_Error +{ + // {{{ properties + + var $error_message_prefix = ''; + var $mode = PEAR_ERROR_RETURN; + var $level = E_USER_NOTICE; + var $code = -1; + var $message = ''; + var $userinfo = ''; + var $backtrace = null; + + // }}} + // {{{ constructor + + /** + * PEAR_Error constructor + * + * @param string $message message + * + * @param int $code (optional) error code + * + * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, + * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION + * + * @param mixed $options (optional) error level, _OR_ in the case of + * PEAR_ERROR_CALLBACK, the callback function or object/method + * tuple. + * + * @param string $userinfo (optional) additional user/debug info + * + * @access public + * + */ + function PEAR_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + if ($mode === null) { + $mode = PEAR_ERROR_RETURN; + } + $this->message = $message; + $this->code = $code; + $this->mode = $mode; + $this->userinfo = $userinfo; + if (!PEAR::getStaticProperty('PEAR_Error', 'skiptrace')) { + $this->backtrace = debug_backtrace(); + if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) { + unset($this->backtrace[0]['object']); + } + } + if ($mode & PEAR_ERROR_CALLBACK) { + $this->level = E_USER_NOTICE; + $this->callback = $options; + } else { + if ($options === null) { + $options = E_USER_NOTICE; + } + $this->level = $options; + $this->callback = null; + } + if ($this->mode & PEAR_ERROR_PRINT) { + if (is_null($options) || is_int($options)) { + $format = "%s"; + } else { + $format = $options; + } + printf($format, $this->getMessage()); + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + trigger_error($this->getMessage(), $this->level); + } + if ($this->mode & PEAR_ERROR_DIE) { + $msg = $this->getMessage(); + if (is_null($options) || is_int($options)) { + $format = "%s"; + if (substr($msg, -1) != "\n") { + $msg .= "\n"; + } + } else { + $format = $options; + } + die(sprintf($format, $msg)); + } + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_callable($this->callback)) { + call_user_func($this->callback, $this); + } + } + if ($this->mode & PEAR_ERROR_EXCEPTION) { + trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING); + eval('$e = new Exception($this->message, $this->code);throw($e);'); + } + } + + // }}} + // {{{ getMode() + + /** + * Get the error mode from an error object. + * + * @return int error mode + * @access public + */ + function getMode() { + return $this->mode; + } + + // }}} + // {{{ getCallback() + + /** + * Get the callback function/method from an error object. + * + * @return mixed callback function or object/method array + * @access public + */ + function getCallback() { + return $this->callback; + } + + // }}} + // {{{ getMessage() + + + /** + * Get the error message from an error object. + * + * @return string full error message + * @access public + */ + function getMessage() + { + return ($this->error_message_prefix . $this->message); + } + + + // }}} + // {{{ getCode() + + /** + * Get error code from an error object + * + * @return int error code + * @access public + */ + function getCode() + { + return $this->code; + } + + // }}} + // {{{ getType() + + /** + * Get the name of this error/exception. + * + * @return string error/exception name (type) + * @access public + */ + function getType() + { + return get_class($this); + } + + // }}} + // {{{ getUserInfo() + + /** + * Get additional user-supplied information. + * + * @return string user-supplied information + * @access public + */ + function getUserInfo() + { + return $this->userinfo; + } + + // }}} + // {{{ getDebugInfo() + + /** + * Get additional debug information supplied by the application. + * + * @return string debug information + * @access public + */ + function getDebugInfo() + { + return $this->getUserInfo(); + } + + // }}} + // {{{ getBacktrace() + + /** + * Get the call backtrace from where the error was generated. + * Supported with PHP 4.3.0 or newer. + * + * @param int $frame (optional) what frame to fetch + * @return array Backtrace, or NULL if not available. + * @access public + */ + function getBacktrace($frame = null) + { + if (defined('PEAR_IGNORE_BACKTRACE')) { + return null; + } + if ($frame === null) { + return $this->backtrace; + } + return $this->backtrace[$frame]; + } + + // }}} + // {{{ addUserInfo() + + function addUserInfo($info) + { + if (empty($this->userinfo)) { + $this->userinfo = $info; + } else { + $this->userinfo .= " ** $info"; + } + } + + // }}} + // {{{ toString() + + /** + * Make a string representation of this object. + * + * @return string a string with an object summary + * @access public + */ + function toString() { + $modes = array(); + $levels = array(E_USER_NOTICE => 'notice', + E_USER_WARNING => 'warning', + E_USER_ERROR => 'error'); + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_array($this->callback)) { + $callback = (is_object($this->callback[0]) ? + strtolower(get_class($this->callback[0])) : + $this->callback[0]) . '::' . + $this->callback[1]; + } else { + $callback = $this->callback; + } + return sprintf('[%s: message="%s" code=%d mode=callback '. + 'callback=%s prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + $callback, $this->error_message_prefix, + $this->userinfo); + } + if ($this->mode & PEAR_ERROR_PRINT) { + $modes[] = 'print'; + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + $modes[] = 'trigger'; + } + if ($this->mode & PEAR_ERROR_DIE) { + $modes[] = 'die'; + } + if ($this->mode & PEAR_ERROR_RETURN) { + $modes[] = 'return'; + } + return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. + 'prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + implode("|", $modes), $levels[$this->level], + $this->error_message_prefix, + $this->userinfo); + } + + // }}} +} + +/* + * Local Variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ +?> diff --git a/plugins/tidypics/lib/phpFlickr/README.txt b/plugins/tidypics/lib/phpFlickr/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..df0a56d98a09ad2c1930669bbe2330c09341da67 --- /dev/null +++ b/plugins/tidypics/lib/phpFlickr/README.txt @@ -0,0 +1,215 @@ +phpFlickr Class 2.3.1 +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("<token string>"); + 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: + + <FilesMatch "\.cache$"> + Deny from all + </FilesMatch> + + 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/plugins/tidypics/lib/phpFlickr/auth.php b/plugins/tidypics/lib/phpFlickr/auth.php new file mode 100644 index 0000000000000000000000000000000000000000..d272d49bf194b63ad11c1be87724a70e69fa9f1a --- /dev/null +++ b/plugins/tidypics/lib/phpFlickr/auth.php @@ -0,0 +1,37 @@ +<?php + /* Last updated with phpFlickr 1.3.1 + * + * Edit these variables to reflect the values you need. $default_redirect + * and $permissions are only important if you are linking here instead of + * using phpFlickr::auth() from another page or if you set the remember_uri + * argument to false. + */ + $api_key = "26b2abba37182aca62fe0eb2c7782050"; + $api_secret = "475e45cc580334da"; + $default_redirect = "/"; + $permissions = "read"; + $path_to_phpFlickr_class = "./"; + + ob_start(); + require_once($path_to_phpFlickr_class . "phpFlickr.php"); + unset($_SESSION['phpFlickr_auth_token']); + + if (!empty($_GET['extra'])) { + $redirect = $_GET['extra']; + } + + $f = new phpFlickr($api_key, $api_secret); + + if (empty($_GET['frob'])) { + $f->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/plugins/tidypics/lib/phpFlickr/example.php b/plugins/tidypics/lib/phpFlickr/example.php new file mode 100644 index 0000000000000000000000000000000000000000..8b409b4251fb29cfba0bb0197f5561a196d598dd --- /dev/null +++ b/plugins/tidypics/lib/phpFlickr/example.php @@ -0,0 +1,30 @@ +<?php +/* Last updated with phpFlickr 1.3.2 + * + * This example file shows you how to call the 100 most recent public + * photos. It parses through them and prints out a link to each of them + * along with the owner's name. + * + * Most of the processing time in this file comes from the 100 calls to + * flickr.people.getInfo. Enabling caching will help a whole lot with + * this as there are many people who post multiple photos at once. + * + * Obviously, you'll want to replace the "<api key>" with one provided + * by Flickr: http://www.flickr.com/services/api/key.gne + */ + +require_once("phpFlickr.php"); +$f = new phpFlickr("<api key>"); + +$recent = $f->photos_getRecent(); + +foreach ($recent['photo'] as $photo) { + $owner = $f->people_getInfo($photo['owner']); + echo "<a href='http://www.flickr.com/photos/" . $photo['owner'] . "/" . $photo['id'] . "/'>"; + echo $photo['title']; + echo "</a> Owner: "; + echo "<a href='http://www.flickr.com/people/" . $photo['owner'] . "/'>"; + echo $owner['username']; + echo "</a><br>"; +} +?> diff --git a/plugins/tidypics/lib/phpFlickr/getToken.php b/plugins/tidypics/lib/phpFlickr/getToken.php new file mode 100644 index 0000000000000000000000000000000000000000..55180ea291ca7f2d38aec94e4da37c3b803e561f --- /dev/null +++ b/plugins/tidypics/lib/phpFlickr/getToken.php @@ -0,0 +1,19 @@ +<?php + /* Last updated with phpFlickr 1.4 + * + * If you need your app to always login with the same user (to see your private + * photos or photosets, for example), you can use this file to login and get a + * token assigned so that you can hard code the token to be used. To use this + * use the phpFlickr::setToken() function whenever you create an instance of + * the class. + */ + + require_once("phpFlickr.php"); + $f = new phpFlickr("26b2abba37182aca62fe0eb2c7782050", "475e45cc580334da"); + + //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/plugins/tidypics/lib/phpFlickr/phpFlickr.php b/plugins/tidypics/lib/phpFlickr/phpFlickr.php new file mode 100644 index 0000000000000000000000000000000000000000..8ef65c581506c17d8a00e0e689e19293710a4b6a --- /dev/null +++ b/plugins/tidypics/lib/phpFlickr/phpFlickr.php @@ -0,0 +1,1453 @@ +<?php +/* phpFlickr Class 2.3.1 + * Written by Dan Coulter (dan@dancoulter.com) + * Project Home Page: http://phpflickr.com/ + * Released under GNU Lesser General Public License (http://www.gnu.org/copyleft/lgpl.html) + * For more information about the class and upcoming tools and toys using it, + * visit http://www.phpflickr.com/ + * + * For installation instructions, open the README.txt file packaged with this + * class. If you don't have a copy, you can see it at: + * http://www.phpflickr.com/README.txt + * + * Please submit all problems or questions to the Help Forum on my Google Code project page: + * http://code.google.com/p/phpflickr/issues/list + * + */ +if (session_id() == "") { + @session_start(); +} + +// Decides which include path delimiter to use. Windows should be using a semi-colon +// and everything else should be using a colon. If this isn't working on your system, +// comment out this if statement and manually set the correct value into $path_delimiter. +if (strpos(__FILE__, ':') !== false) { + $path_delimiter = ';'; +} else { + $path_delimiter = ':'; +} + +// This will add the packaged PEAR files into the include path for PHP, allowing you +// to use them transparently. This will prefer officially installed PEAR files if you +// have them. If you want to prefer the packaged files (there shouldn't be any reason +// to), swap the two elements around the $path_delimiter variable. If you don't have +// the PEAR packages installed, you can leave this like it is and move on. + +ini_set('include_path', ini_get('include_path') . $path_delimiter . dirname(__FILE__) . '/PEAR'); + +// If you have problems including the default PEAR install (like if your open_basedir +// setting doesn't allow you to include files outside of your web root), comment out +// the line above and uncomment the next line: + +// ini_set('include_path', dirname(__FILE__) . '/PEAR' . $path_delimiter . ini_get('include_path')); + +class phpFlickr { + var $api_key; + var $secret; + var $REST = 'http://api.flickr.com/services/rest/'; + var $Upload = 'http://api.flickr.com/services/upload/'; + var $Replace = 'http://api.flickr.com/services/replace/'; + var $req; + var $response; + var $parsed_response; + var $cache = false; + var $cache_db = null; + var $cache_table = null; + var $cache_dir = null; + var $cache_expire = null; + var $die_on_error; + var $error_code; + Var $error_msg; + var $token; + var $php_version; + + /* + * When your database cache table hits this many rows, a cleanup + * will occur to get rid of all of the old rows and cleanup the + * garbage in the table. For most personal apps, 1000 rows should + * be more than enough. If your site gets hit by a lot of traffic + * or you have a lot of disk space to spare, bump this number up. + * You should try to set it high enough that the cleanup only + * happens every once in a while, so this will depend on the growth + * of your table. + */ + var $max_cache_rows = 1000; + + function phpFlickr ($api_key, $secret = NULL, $die_on_error = false) { + //The API Key must be set before any calls can be made. You can + //get your own at http://www.flickr.com/services/api/misc.api_keys.html + $this->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]); + + //All calls to the API are done via the POST method using the PEAR::HTTP_Request package. + require_once 'HTTP/Request.php'; + $this->req =& new HTTP_Request(); + $this->req->setMethod(HTTP_REQUEST_METHOD_POST); + } + + 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') { + require_once 'DB.php'; + $db =& DB::connect($connection); + if (PEAR::isError($db)) { + die($db->getMessage()); + } + + /* + * If high performance is crucial, you can easily comment + * out this query once you've created your database table. + */ + + $db->query(" + CREATE TABLE IF NOT EXISTS `$table` ( + `request` CHAR( 35 ) NOT NULL , + `response` MEDIUMTEXT NOT NULL , + `expiration` DATETIME NOT NULL , + INDEX ( `request` ) + ) TYPE = MYISAM"); + + if ($db->getOne("SELECT COUNT(*) FROM $table") > $this->max_cache_rows) { + $db->query("DELETE FROM $table WHERE expiration < DATE_SUB(NOW(), INTERVAL $cache_expire second)"); + $db->query('OPTIMIZE TABLE ' . $this->cache_table); + } + + $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); + } + } + } + } + $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. + $reqhash = md5(serialize($request)); + if ($this->cache == 'db') { + $result = $this->cache_db->getOne("SELECT response FROM " . $this->cache_table . " WHERE request = ? AND DATE_SUB(NOW(), INTERVAL " . (int) $this->cache_expire . " SECOND) < expiration", $reqhash); + if (!empty($result)) { + return $result; + } + } 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)); + } + } + } + return false; + } + + function cache ($request, $response) { + //Caches the unparsed XML of a request. + $reqhash = md5(serialize($request)); + if ($this->cache == 'db') { + //$this->cache_db->query("DELETE FROM $this->cache_table WHERE request = '$reqhash'"); + if ($this->cache_db->getOne("SELECT COUNT(*) FROM {$this->cache_table} WHERE request = '$reqhash'")) { + $sql = "UPDATE " . $this->cache_table . " SET response = ?, expiration = ? WHERE request = ?"; + $this->cache_db->query($sql, array($response, strftime("%Y-%m-%d %H:%M:%S"), $reqhash)); + } else { + $sql = "INSERT INTO " . $this->cache_table . " (request, response, expiration) VALUES ('$reqhash', '" . str_replace("'", "''", $response) . "', '" . strftime("%Y-%m-%d %H:%M:%S") . "')"; + $this->cache_db->query($sql); + } + } elseif ($this->cache == "fs") { + $file = $this->cache_dir . "/" . $reqhash . ".cache"; + $fstream = fopen($file, "w"); + $result = fwrite($fstream,$response); + fclose($fstream); + return $result; + } + return false; + } + + function request ($command, $args = array(), $nocache = false) { + //Sends a request to Flickr's REST endpoint via POST. + $this->req->setURL($this->REST); + $this->req->clearPostData(); + 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 = ""; + if (!($this->response = $this->getCached($args)) || $nocache) { + foreach ($args as $key => $data) { + $auth_sig .= $key . $data; + $this->req->addPostData($key, $data); + } + if (!empty($this->secret)) { + $api_sig = md5($this->secret . $auth_sig); + $this->req->addPostData("api_sig", $api_sig); + } + + $this->req->addHeader("Connection", "Keep-Alive"); + + //Send Requests + if ($this->req->sendRequest()) { + $this->response = $this->req->getResponseBody(); + $this->cache($args, $this->response); + } else { + die("There has been a problem sending your command to the server."); + } + } + /* + * 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", + "thumbnail" => "_t", + "small" => "_m", + "medium" => "", + "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) { + $upload_req =& new HTTP_Request(); + $upload_req->setMethod(HTTP_REQUEST_METHOD_POST); + + + $upload_req->setURL($this->Upload); + $upload_req->clearPostData(); + + //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->email)) { + $args = array_merge($args, array("email" => $this->email)); + } + if (!empty($this->password)) { + $args = array_merge($args, array("password" => $this->password)); + } + 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 ($data !== null) { + $auth_sig .= $key . $data; + $upload_req->addPostData($key, $data); + } + } + if (!empty($this->secret)) { + $api_sig = md5($this->secret . $auth_sig); + $upload_req->addPostData("api_sig", $api_sig); + } + + $photo = realpath($photo); + + $result = $upload_req->addFile("photo", $photo); + + if (PEAR::isError($result)) { + die($result->getMessage()); + } + + //Send Requests + if ($upload_req->sendRequest()) { + $this->response = $upload_req->getResponseBody(); + } else { + die("There has been a problem sending your command to the server."); + } + + $rsp = explode("\n", $this->response); + foreach ($rsp as $line) { + if (ereg('<err code="([0-9]+)" msg="(.*)"', $line, $match)) { + if ($this->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("<photoid>(.*)</photoid>", $line, $match)) { + $this->error_code = false; + $this->error_msg = false; + return $match[1]; + } + } + } + + function async_upload ($photo, $title = null, $description = null, $tags = null, $is_public = null, $is_friend = null, $is_family = null) { + $upload_req =& new HTTP_Request(); + $upload_req->setMethod(HTTP_REQUEST_METHOD_POST); + + $upload_req->setURL($this->Upload); + $upload_req->clearPostData(); + + //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->email)) { + $args = array_merge($args, array("email" => $this->email)); + } + if (!empty($this->password)) { + $args = array_merge($args, array("password" => $this->password)); + } + 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 ($data !== null) { + $auth_sig .= $key . $data; + $upload_req->addPostData($key, $data); + } + } + if (!empty($this->secret)) { + $api_sig = md5($this->secret . $auth_sig); + $upload_req->addPostData("api_sig", $api_sig); + } + + $photo = realpath($photo); + + $result = $upload_req->addFile("photo", $photo); + + if (PEAR::isError($result)) { + die($result->getMessage()); + } + + //Send Requests + if ($upload_req->sendRequest()) { + $this->response = $upload_req->getResponseBody(); + } else { + die("There has been a problem sending your command to the server."); + } + + $rsp = explode("\n", $this->response); + foreach ($rsp as $line) { + if (ereg('<err code="([0-9]+)" msg="(.*)"', $line, $match)) { + if ($this->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("<ticketid>(.*)</", $line, $match)) { + $this->error_code = false; + $this->error_msg = false; + return $match[1]; + } + } + } + + // Interface for new replace API method. + function replace ($photo, $photo_id, $async = null) { + $upload_req =& new HTTP_Request(); + $upload_req->setMethod(HTTP_REQUEST_METHOD_POST); + + $upload_req->setURL($this->Replace); + $upload_req->clearPostData(); + + //Process arguments, including method and login data. + $args = array("api_key" => $this->api_key, "photo_id" => $photo_id, "async" => $async); + if (!empty($this->email)) { + $args = array_merge($args, array("email" => $this->email)); + } + if (!empty($this->password)) { + $args = array_merge($args, array("password" => $this->password)); + } + 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 ($data !== null) { + $auth_sig .= $key . $data; + $upload_req->addPostData($key, $data); + } + } + if (!empty($this->secret)) { + $api_sig = md5($this->secret . $auth_sig); + $upload_req->addPostData("api_sig", $api_sig); + } + + $photo = realpath($photo); + + $result = $upload_req->addFile("photo", $photo); + + if (PEAR::isError($result)) { + die($result->getMessage()); + } + + //Send Requests + if ($upload_req->sendRequest()) { + $this->response = $upload_req->getResponseBody(); + } else { + die("There has been a problem sending your command to the server."); + } + if ($async == 1) + $find = 'ticketid'; + else + $find = 'photoid'; + + $rsp = explode("\n", $this->response); + foreach ($rsp as $line) { + if (ereg('<err code="([0-9]+)" msg="(.*)"', $line, $match)) { + if ($this->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("<" . $find . ">(.*)</", $line, $match)) { + $this->error_code = false; + $this->error_msg = false; + return $match[1]; + } + } + } + + 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) { + $redirect = $_SERVER['REQUEST_URI']; + } + $api_sig = md5($this->secret . "api_key" . $this->api_key . "extra" . $redirect . "perms" . $perms); + if ($this->service == "23") { + header("Location: http://www.23hq.com/services/auth/?api_key=" . $this->api_key . "&extra=" . $redirect . "&perms=" . $perms . "&api_sig=". $api_sig); + } else { + header("Location: http://www.flickr.com/services/auth/?api_key=" . $this->api_key . "&extra=" . $redirect . "&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_register('phpFlickr_auth_token'); + $_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, $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, '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, $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, '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) { + /* http://www.flickr.com/services/api/flickr.favorites.remove.html */ + $this->request("flickr.favorites.remove", array("photo_id"=>$photo_id), TRUE); + return $this->parsed_response ? true : false; + } + + /* 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) { + /* http://www.flickr.com/services/api/flickr.groups.pools.getContext.html */ + $this->request("flickr.groups.pools.getContext", array("photo_id"=>$photo_id, "group_id"=>$group_id)); + return $this->parsed_response ? $this->parsed_response : false; + } + + 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, $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); + } + $this->request("flickr.groups.pools.getPhotos", array("group_id"=>$group_id, "tags"=>$tags, "user_id"=>$user_id, "extras"=>$extras, "per_page"=>$per_page, "page"=>$page)); + return $this->parsed_response ? $this->parsed_response['photos'] : false; + } + + 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, $extras = NULL, $per_page = NULL, $page = NULL) { + /* http://www.flickr.com/services/api/flickr.interestingness.getList.html */ + if (is_array($extras)) { + $extras = implode(",", $extras); + } + + $this->request("flickr.interestingness.getList", array("date"=>$date, "extras"=>$extras, "per_page"=>$per_page, "page"=>$page)); + return $this->parsed_response ? $this->parsed_response['photos'] : false; + } + + /* 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) { + /* 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)); + } + + /* 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_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) { + /* http://www.flickr.com/services/api/flickr.photos.getContext.html */ + $this->request("flickr.photos.getContext", array("photo_id"=>$photo_id)); + return $this->parsed_response ? $this->parsed_response : false; + } + + 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) { + /* http://www.flickr.com/services/api/flickr.photos.getInfo.html */ + $this->request("flickr.photos.getInfo", array("photo_id"=>$photo_id, "secret"=>$secret)); + return $this->parsed_response ? $this->parsed_response['photo'] : false; + } + + function photos_getNotInSet ($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.getNotInSet.html */ + return $this->call('flickr.photos.getNotInSet', 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_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 ($extras = NULL, $per_page = NULL, $page = NULL) { + /* http://www.flickr.com/services/api/flickr.photos.getRecent.html */ + + if (is_array($extras)) { + $extras = implode(",", $extras); + } + $this->request("flickr.photos.getRecent", array("extras"=>$extras, "per_page"=>$per_page, "page"=>$page)); + return $this->parsed_response ? $this->parsed_response['photos'] : false; + } + + 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) { + /* 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)); + } + + 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) { + /* 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)); + } + + 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 - 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) { + /* http://www.flickr.com/services/api/flickr.photosets.getContext.html */ + $this->request("flickr.photosets.getContext", array("photo_id" => $photo_id, "photoset_id" => $photoset_id)); + return $this->parsed_response ? $this->parsed_response : false; + } + + 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; + } + + /* 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) { + /* 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)); + } + + 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; + } + + /* 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_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; + } +} + + +?> diff --git a/plugins/tidypics/lib/resize.php b/plugins/tidypics/lib/resize.php new file mode 100644 index 0000000000000000000000000000000000000000..857d0ba1cc93dffc8f5eb8a16a864f6e2c051e93 --- /dev/null +++ b/plugins/tidypics/lib/resize.php @@ -0,0 +1,537 @@ +<?php +/** + * Elgg tidypics library of resizing functions + * + * @package TidypicsImageResize + */ + +include dirname(__FILE__) . "/watermark.php"; + + +/** + * Create thumbnails using PHP GD Library + * + * @param ElggFile holds the image that was uploaded + * @param string folder to store thumbnail in + * @param string name of the thumbnail + * @return bool TRUE on success + */ +function tp_create_gd_thumbnails($file, $prefix, $filestorename) { + global $CONFIG; + + $image_sizes = get_plugin_setting('image_sizes', 'tidypics'); + if (!$image_sizes) { + // move this out of library + register_error(elgg_echo('tidypics:nosettings')); + forward($_SERVER['HTTP_REFERER']); + return FALSE; + } + $image_sizes = unserialize($image_sizes); + + $thumb = new ElggFile(); + $thumb->owner_guid = $file->owner_guid; + $thumb->container_guid = $file->container_guid; + + // tiny thumbail + $thumb->setFilename($prefix."thumb".$filestorename); + $thumbname = $thumb->getFilenameOnFilestore(); + $rtn_code = tp_gd_resize( $file->getFilenameOnFilestore(), + $thumbname, + FALSE, + $image_sizes['thumb_image_width'], + $image_sizes['thumb_image_height'], + TRUE); + if (!$rtn_code) { + return FALSE; + } + $file->thumbnail = $prefix."thumb".$filestorename; + + // album thumbnail + global $CONFIG; + $CONFIG->debug = 'WARNING'; + $thumb->setFilename($prefix."smallthumb".$filestorename); + $thumbname = $thumb->getFilenameOnFilestore(); + $rtn_code = tp_gd_resize( $file->getFilenameOnFilestore(), + $thumbname, + FALSE, + $image_sizes['small_image_width'], + $image_sizes['small_image_height'], + TRUE); + if (!$rtn_code) { + return FALSE; + } + $file->smallthumb = $prefix."smallthumb".$filestorename; + unset($CONFIG->debug); + + // main image + $thumb->setFilename($prefix."largethumb".$filestorename); + $thumbname = $thumb->getFilenameOnFilestore(); + $rtn_code = tp_gd_resize( $file->getFilenameOnFilestore(), + $thumbname, + TRUE, + $image_sizes['large_image_width'], + $image_sizes['large_image_height'], + FALSE); + if (!$rtn_code) { + return FALSE; + } + $file->largethumb = $prefix."largethumb".$filestorename; + + + unset($thumb); + + return TRUE; +} + +/** + * Writes resized version of an already uploaded image - original from Elgg filestore.php + * Saves it in the same format as uploaded + * + * @param string $input_name The name of the file on the disk + * @param string $output_name The name of the file to be written + * @param bool - watermark this image? + * @param int $maxwidth The maximum width of the resized image + * @param int $maxheight The maximum height of the resized image + * @param TRUE|FALSE $square If set to TRUE, will take the smallest of maxwidth and maxheight and use it to set the dimensions on all size; the image will be cropped. + * @return bool TRUE on success or FALSE on failure + */ +function tp_gd_resize($input_name, $output_name, $watermark, $maxwidth, $maxheight, $square = FALSE, $x1 = 0, $y1 = 0, $x2 = 0, $y2 = 0) { + + // Get the size information from the image + $imgsizearray = getimagesize($input_name); + if (!$imgsizearray) { + return FALSE; + } + + // Get width and height of image + $width = $imgsizearray[0]; + $height = $imgsizearray[1]; + + $params = tp_im_calc_resize_params($width, $height, $maxwidth, $maxheight, $square, $x1, $y1, $x2, $y2); + if (!$params) { + return FALSE; + } + + $new_width = $params['new_width']; + $new_height = $params['new_height']; + $region_width = $params['region_width']; + $region_height = $params['region_height']; + $widthoffset = $params['width_offset']; + $heightoffset = $params['height_offset']; + + $accepted_formats = array( + 'image/jpeg' => 'jpeg', + 'image/pjpeg' => 'jpeg', + 'image/png' => 'png', + 'image/x-png' => 'png', + 'image/gif' => 'gif' + ); + + // make sure the function is available + $function = "imagecreatefrom" . $accepted_formats[$imgsizearray['mime']]; + if (!is_callable($function)) { + return FALSE; + } + + // load old image + $oldimage = $function($input_name); + if (!$oldimage) { + return FALSE; + } + + // allocate the new image + $newimage = imagecreatetruecolor($new_width, $new_height); + if (!$newimage) { + return FALSE; + } + + $rtn_code = imagecopyresampled( $newimage, + $oldimage, + 0, + 0, + $widthoffset, + $heightoffset, + $new_width, + $new_height, + $region_width, + $region_height); + if (!$rtn_code) { + return $rtn_code; + } + + if ($watermark) { + tp_gd_watermark($newimage); + } + + switch ($imgsizearray['mime']) { + case 'image/jpeg': + case 'image/pjpeg': + $rtn_code = imagejpeg($newimage, $output_name, 85); + break; + case 'image/png': + case 'image/x-png': + $rtn_code = imagepng($newimage, $output_name); + break; + case 'image/gif': + $rtn_code = imagegif($newimage, $output_name); + break; + } + + imagedestroy($newimage); + imagedestroy($oldimage); + + return $rtn_code; +} + + +/** + * Create thumbnails using PHP imagick extension + * + * @param ElggFile holds the image that was uploaded + * @param string folder to store thumbnail in + * @param string name of the thumbnail + * @return bool TRUE on success + */ +function tp_create_imagick_thumbnails($file, $prefix, $filestorename) { + $image_sizes = get_plugin_setting('image_sizes', 'tidypics'); + if (!$image_sizes) { + register_error(elgg_echo('tidypics:nosettings')); + return FALSE; + } + $image_sizes = unserialize($image_sizes); + + $thumb = new ElggFile(); + $thumb->owner_guid = $file->owner_guid; + $thumb->container_guid = $file->container_guid; + + // tiny thumbnail + $thumb->setFilename($prefix."thumb".$filestorename); + $thumbname = $thumb->getFilenameOnFilestore(); + $rtn_code = tp_imagick_resize( $file->getFilenameOnFilestore(), + $thumbname, + $image_sizes['thumb_image_width'], + $image_sizes['thumb_image_height'], + TRUE); + if (!$rtn_code) { + return FALSE; + } + $file->thumbnail = $prefix."thumb".$filestorename; + + // album thumbnail + $thumb->setFilename($prefix."smallthumb".$filestorename); + $thumbname = $thumb->getFilenameOnFilestore(); + $rtn_code = tp_imagick_resize( $file->getFilenameOnFilestore(), + $thumbname, + $image_sizes['small_image_width'], + $image_sizes['small_image_height'], + TRUE); + if (!$rtn_code) { + return FALSE; + } + $file->smallthumb = $prefix."smallthumb".$filestorename; + + // main image + $thumb->setFilename($prefix."largethumb".$filestorename); + $thumbname = $thumb->getFilenameOnFilestore(); + $rtn_code = tp_imagick_resize( $file->getFilenameOnFilestore(), + $thumbname, + $image_sizes['large_image_width'], + $image_sizes['large_image_height'], + FALSE); + if (!$rtn_code) { + return FALSE; + } + $file->largethumb = $prefix."largethumb".$filestorename; + + tp_imagick_watermark($thumbname); + + unset($thumb); + + return TRUE; +} + + +/** + * Resize using PHP imagick extension + * + * Writes resized version of an already uploaded image + * + * + * @param string $input_name The name of the file input field on the submission form + * @param string $output_name The name of the file to be written + * @param int $maxwidth The maximum width of the resized image + * @param int $maxheight The maximum height of the resized image + * @param TRUE|FALSE $square If set to TRUE, will take the smallest of maxwidth and maxheight and use it to set the dimensions on all size; the image will be cropped. + * @return bool TRUE on success + */ +function tp_imagick_resize($input_name, $output_name, $maxwidth, $maxheight, $square = FALSE, $x1 = 0, $y1 = 0, $x2 = 0, $y2 = 0) { + + // Get the size information from the image + $imgsizearray = getimagesize($input_name); + if (!$imgsizearray) { + return FALSE; + } + + // Get width and height + $width = $imgsizearray[0]; + $height = $imgsizearray[1]; + + $params = tp_im_calc_resize_params($width, $height, $maxwidth, $maxheight, $square, $x1, $y1, $x2, $y2); + if (!$params) { + return FALSE; + } + + $new_width = $params['new_width']; + $new_height = $params['new_height']; + $region_width = $params['region_width']; + $region_height = $params['region_height']; + $widthoffset = $params['width_offset']; + $heightoffset = $params['height_offset']; + + try { + $img = new Imagick($input_name); + } catch (ImagickException $e) { + return FALSE; + } + + $img->cropImage($region_width, $region_height, $widthoffset, $heightoffset); + + // use the default IM filter (windowing filter), I think 1 means default blurring or number of lobes + $img->resizeImage($new_width, $new_height, imagick::FILTER_LANCZOS, 1); + $img->setImagePage($new_width, $new_height, 0, 0); + + if ($img->writeImage($output_name) != TRUE) { + $img->destroy(); + return FALSE; + } + + $img->destroy(); + + return TRUE; +} + +/** + * Create thumbnails using ImageMagick executables + * + * @param ElggFile holds the image that was uploaded + * @param string folder to store thumbnail in + * @param string name of the thumbnail + * @return bool TRUE on success + */ +function tp_create_im_cmdline_thumbnails($file, $prefix, $filestorename) { + $image_sizes = get_plugin_setting('image_sizes', 'tidypics'); + if (!$image_sizes) { + register_error(elgg_echo('tidypics:nosettings')); + return FALSE; + } + $image_sizes = unserialize($image_sizes); + + $thumb = new ElggFile(); + $thumb->owner_guid = $file->owner_guid; + $thumb->container_guid = $file->container_guid; + + // tiny thumbnail + $thumb->setFilename($prefix."thumb".$filestorename); + $thumbname = $thumb->getFilenameOnFilestore(); + $rtn_code = tp_im_cmdline_resize( $file->getFilenameOnFilestore(), + $thumbname, + $image_sizes['thumb_image_width'], + $image_sizes['thumb_image_height'], + TRUE); + if (!$rtn_code) { + return FALSE; + } + $file->thumbnail = $prefix."thumb".$filestorename; + + + // album thumbnail + $thumb->setFilename($prefix."smallthumb".$filestorename); + $thumbname = $thumb->getFilenameOnFilestore(); + $rtn_code = tp_im_cmdline_resize( $file->getFilenameOnFilestore(), + $thumbname, + $image_sizes['small_image_width'], + $image_sizes['small_image_height'], + TRUE); + if (!$rtn_code) { + return FALSE; + } + $file->smallthumb = $prefix."smallthumb".$filestorename; + + // main image + $thumb->setFilename($prefix."largethumb".$filestorename); + $thumbname = $thumb->getFilenameOnFilestore(); + $rtn_code = tp_im_cmdline_resize( $file->getFilenameOnFilestore(), + $thumbname, + $image_sizes['large_image_width'], + $image_sizes['large_image_height'], + FALSE); + if (!$rtn_code) { + return FALSE; + } + $file->largethumb = $prefix."largethumb".$filestorename; + + + tp_im_cmdline_watermark($thumbname); + + unset($thumb); + + return TRUE; +} + +/** + * Gets the jpeg contents of the resized version of an already uploaded image + * (Returns FALSE if the uploaded file was not an image) + * + * @param string $input_name The name of the file input field on the submission form + * @param string $output_name The name of the file to be written + * @param int $maxwidth The maximum width of the resized image + * @param int $maxheight The maximum height of the resized image + * @param TRUE|FALSE $square If set to TRUE, will take the smallest of maxwidth and maxheight and use it to set the dimensions on all size; the image will be cropped. + * @return bool + */ +function tp_im_cmdline_resize($input_name, $output_name, $maxwidth, $maxheight, $square = FALSE, $x1 = 0, $y1 = 0, $x2 = 0, $y2 = 0) { + + + // Get the size information from the image + $imgsizearray = getimagesize($input_name); + if (!$imgsizearray) { + return FALSE; + } + + // Get width and height + $orig_width = $imgsizearray[0]; + $orig_height = $imgsizearray[1]; + + $params = tp_im_calc_resize_params($orig_width, $orig_height, $maxwidth, $maxheight, $square, $x1, $y1, $x2, $y2); + if (!$params) { + return FALSE; + } + + $newwidth = $params['new_width']; + $newheight = $params['new_height']; + + $accepted_formats = array( + 'image/jpeg' => 'jpeg', + 'image/pjpeg' => 'jpeg', + 'image/png' => 'png', + 'image/x-png' => 'png', + 'image/gif' => 'gif' + ); + + // If it's a file we can manipulate ... + if (!array_key_exists($imgsizearray['mime'],$accepted_formats)) { + return FALSE; + } + + $im_path = get_plugin_setting('im_path', 'tidypics'); + if (!$im_path) { + $im_path = "/usr/bin/"; + } + if (substr($im_path, strlen($im_path)-1, 1) != "/") { + $im_path .= "/"; + } + + // see imagemagick web site for explanation of these parameters + // the ^ in the resize means those are minimum width and height values + $command = $im_path . "convert \"$input_name\" -resize ".$newwidth."x".$newheight."^ -gravity center -extent ".$newwidth."x".$newheight." \"$output_name\""; + $output = array(); + $ret = 0; + exec($command, $output, $ret); + if ($ret == 127) { + trigger_error('Tidypics warning: Image Magick convert is not found', E_USER_WARNING); + return FALSE; + } else if ($ret > 0) { + trigger_error('Tidypics warning: Image Magick convert failed', E_USER_WARNING); + return FALSE; + } + + return TRUE; +} + +/** + * Calculate the resizing/cropping parameters + * + * @param int $orig_width + * @param int $orig_height + * @param int $new_width + * @param int $new_height + * @param bool $square + * @param int $x1 + * @param int $y1 + * @param int $x2 + * @param int $y2 + * @return array|FALSE + */ +function tp_im_calc_resize_params($orig_width, $orig_height, $new_width, $new_height, $square = FALSE, $x1 = 0, $y1 = 0, $x2 = 0, $y2 = 0) { + // crop image first? + $crop = TRUE; + if ($x1 == 0 && $y1 == 0 && $x2 == 0 && $y2 == 0) { + $crop = FALSE; + } + + // how large a section of the image has been selected + if ($crop) { + $region_width = $x2 - $x1; + $region_height = $y2 - $y1; + } else { + // everything selected if no crop parameters + $region_width = $orig_width; + $region_height = $orig_height; + } + + // determine cropping offsets + if ($square) { + // asking for a square image back + + // detect case where someone is passing crop parameters that are not for a square + if ($crop == TRUE && $region_width != $region_height) { + return FALSE; + } + + // size of the new square image + $new_width = $new_height = min($new_width, $new_height); + + // find largest square that fits within the selected region + $region_width = $region_height = min($region_width, $region_height); + + // set offsets for crop + if ($crop) { + $widthoffset = $x1; + $heightoffset = $y1; + $orig_width = $x2 - $x1; + $orig_height = $orig_width; + } else { + // place square region in the center + $widthoffset = floor(($orig_width - $region_width) / 2); + $heightoffset = floor(($orig_height - $region_height) / 2); + } + } else { + // non-square new image + + // maintain aspect ratio of original image/crop + if (($region_height / (float)$new_height) > ($region_width / (float)$new_width)) { + $new_width = floor($new_height * $region_width / (float)$region_height); + } else { + $new_height = floor($new_width * $region_height / (float)$region_width); + } + + // by default, use entire image + $widthoffset = 0; + $heightoffset = 0; + + if ($crop) { + $widthoffset = $x1; + $heightoffset = $y1; + } + } + + $resize_params = array(); + $resize_params['new_width'] = $new_width; + $resize_params['new_height'] = $new_height; + $resize_params['region_width'] = $region_width; + $resize_params['region_height'] = $region_height; + $resize_params['width_offset'] = $widthoffset; + $resize_params['height_offset'] = $heightoffset; + + return $resize_params; +} \ No newline at end of file diff --git a/plugins/tidypics/lib/tidypics.php b/plugins/tidypics/lib/tidypics.php new file mode 100644 index 0000000000000000000000000000000000000000..539db451a0390859758761440e7291215119f344 --- /dev/null +++ b/plugins/tidypics/lib/tidypics.php @@ -0,0 +1,295 @@ +<?php +/** + * Elgg tidypics library of common functions + * + * @package TidypicsCommon + */ + +/** + * Get images for display on front page + * + * @param int number of images + * @param int (optional) guid of owner + * @return string of html for display + * + * To use with the custom index plugin, use something like this: + + if (is_plugin_enabled('tidypics')) { + ?> + <!-- display latest photos --> + <div class="index_box"> + <h2><a href="<?php echo $vars['url']; ?>pg/photos/world/"><?php echo elgg_echo("tidypics:mostrecent"); ?></a></h2> + <div class="contentWrapper"> + <?php + echo tp_get_latest_photos(5); + ?> + </div> + </div> + <?php + } + ?> + + * Good luck + */ +function tp_get_latest_photos($num_images, $owner_guid = 0) { + $prev_context = set_context('front'); + $image_html = tp_list_entities('object', 'image', $owner_guid, null, $num_images, false, false, false); + set_context($prev_context); + return $image_html; +} + + +/** + * Get image directory path + * + * Each album gets a subdirectory based on its container id + * + * @return string path to image directory + */ +function tp_get_img_dir() { + $file = new ElggFile(); + return $file->getFilenameOnFilestore() . 'image/'; +} + + + +/********************************************************************* + * the functions below replace broken core functions or add functions + * that could/should exist in the core + */ + +/** + * + */ +function tp_get_entities($type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null, $timelower = 0, $timeupper = 0) { + global $CONFIG; + + if ($subtype === false || $subtype === null || $subtype === 0) + return false; + + if ($order_by == "") $order_by = "time_created desc"; + $order_by = sanitise_string($order_by); + $limit = (int)$limit; + $offset = (int)$offset; + $site_guid = (int) $site_guid; + $timelower = (int) $timelower; + $timeupper = (int) $timeupper; + if ($site_guid == 0) + $site_guid = $CONFIG->site_guid; + + $where = array(); + + if (is_array($subtype)) { + $tempwhere = ""; + if (sizeof($subtype)) + foreach($subtype as $typekey => $subtypearray) { + foreach($subtypearray as $subtypeval) { + $typekey = sanitise_string($typekey); + if (!empty($subtypeval)) { + if (!$subtypeval = (int) get_subtype_id($typekey, $subtypeval)) + return false; + } else { + // @todo: Setting subtype to 0 when $subtype = '' returns entities with + // no subtype. This is different to the non-array behavior + // but may be required in some cases. + $subtypeval = 0; + } + if (!empty($tempwhere)) $tempwhere .= " or "; + $tempwhere .= "(type = '{$typekey}' and subtype = {$subtypeval})"; + } + } + if (!empty($tempwhere)) $where[] = "({$tempwhere})"; + + } else { + + $type = sanitise_string($type); + if ($subtype !== "" AND !$subtype = get_subtype_id($type, $subtype)) + return false; + + if ($type != "") + $where[] = "type='$type'"; + if ($subtype!=="") + $where[] = "subtype=$subtype"; + } + + if ($owner_guid != "") { + if (!is_array($owner_guid)) { + $owner_array = array($owner_guid); + $owner_guid = (int) $owner_guid; + $where[] = "owner_guid = '$owner_guid'"; + } else if (sizeof($owner_guid) > 0) { + $owner_array = array_map('sanitise_int', $owner_guid); + // Cast every element to the owner_guid array to int + $owner_guid = array_map("sanitise_int", $owner_guid); + $owner_guid = implode(",",$owner_guid); + $where[] = "owner_guid in ({$owner_guid})"; + } + } + if ($site_guid > 0) + $where[] = "site_guid = {$site_guid}"; + + if (!is_null($container_guid)) { + if (is_array($container_guid)) { + foreach($container_guid as $key => $val) $container_guid[$key] = (int) $val; + $where[] = "container_guid in (" . implode(",",$container_guid) . ")"; + } else { + $container_guid = (int) $container_guid; + $where[] = "container_guid = {$container_guid}"; + } + } + if ($timelower) + $where[] = "time_created >= {$timelower}"; + if ($timeupper) + $where[] = "time_created <= {$timeupper}"; + + if (!$count) { + $query = "SELECT * from {$CONFIG->dbprefix}entities where "; + } else { + $query = "SELECT count(guid) as total from {$CONFIG->dbprefix}entities where "; + } + foreach ($where as $w) + $query .= " $w and "; + $query .= get_access_sql_suffix(); // Add access controls + + if (!$count) { + $query .= " order by $order_by"; + if ($limit) $query .= " limit $offset, $limit"; // Add order and limit + $dt = get_data($query, "entity_row_to_elggstar"); + return $dt; + } else { + $total = get_data_row($query); + return $total->total; + } +} + +function tp_list_entities($type= "", $subtype = "", $owner_guid = 0, $container_guid = null, $limit = 10, $fullview = true, $viewtypetoggle = false, $pagination = true) { + + $offset = (int) get_input('offset'); + $count = tp_get_entities($type, $subtype, $owner_guid, "", $limit, $offset, true, 0, $container_guid); + + $entities = tp_get_entities($type, $subtype, $owner_guid, "", $limit, $offset, false, 0, $container_guid); + + return tp_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $pagination); +} + +function tp_view_entity_list($entities, $count, $offset, $limit, $fullview = true, $viewtypetoggle = false, $pagination = true) { + $context = get_context(); + + $html = elgg_view('tidypics/gallery',array( + 'entities' => $entities, + 'count' => $count, + 'offset' => $offset, + 'limit' => $limit, + 'baseurl' => $_SERVER['REQUEST_URI'], + 'fullview' => $fullview, + 'context' => $context, + 'viewtypetoggle' => $viewtypetoggle, + 'viewtype' => get_input('search_viewtype','list'), + 'pagination' => $pagination + )); + + return $html; +} + +function tp_get_entities_from_annotations_calculate_x($sum = "sum", $entity_type = "", $entity_subtype = "", $name = "", $mdname = '', $mdvalue = '', $owner_guid = 0, $limit = 10, $offset = 0, $orderdir = 'desc', $count = false) { + global $CONFIG; + + $sum = sanitise_string($sum); + $entity_type = sanitise_string($entity_type); + $entity_subtype = get_subtype_id($entity_type, $entity_subtype); + $name = get_metastring_id($name); + $limit = (int) $limit; + $offset = (int) $offset; + $owner_guid = (int) $owner_guid; + if (!empty($mdname) && !empty($mdvalue)) { + $meta_n = get_metastring_id($mdname); + $meta_v = get_metastring_id($mdvalue); + } + + if (empty($name)) return 0; + + $where = array(); + + if ($entity_type!="") + $where[] = "e.type='$entity_type'"; + if ($owner_guid > 0) + $where[] = "e.owner_guid = $owner_guid"; + if ($entity_subtype) + $where[] = "e.subtype=$entity_subtype"; + if ($name!="") + $where[] = "a.name_id='$name'"; + + if (!empty($mdname) && !empty($mdvalue)) { + if ($mdname!="") + $where[] = "m.name_id='$meta_n'"; + if ($mdvalue!="") + $where[] = "m.value_id='$meta_v'"; + } + + if ($sum != "count") + $where[] = "a.value_type='integer'"; // Limit on integer types + + if (!$count) { + $query = "SELECT distinct e.*, $sum(ms.string) as sum "; + } else { + $query = "SELECT count(distinct e.guid) as num, $sum(ms.string) as sum "; + } + $query .= " from {$CONFIG->dbprefix}entities e JOIN {$CONFIG->dbprefix}annotations a on a.entity_guid = e.guid JOIN {$CONFIG->dbprefix}metastrings ms on a.value_id=ms.id "; + + if (!empty($mdname) && !empty($mdvalue)) { + $query .= " JOIN {$CONFIG->dbprefix}metadata m on m.entity_guid = e.guid "; + } + + $query .= " WHERE "; + foreach ($where as $w) + $query .= " $w and "; + $query .= get_access_sql_suffix("a"); // now add access + $query .= ' and ' . get_access_sql_suffix("e"); // now add access + if (!$count) $query .= ' group by e.guid'; + + if (!$count) { + $query .= ' order by sum ' . $orderdir; + $query .= ' limit ' . $offset . ' , ' . $limit; + return get_data($query, "entity_row_to_elggstar"); + } else { + if ($row = get_data_row($query)) { + return $row->num; + } + } + return false; +} + +/** + * Is page owner a group - convenience function + * + * @return true/false + */ +function tp_is_group_page() { + + if ($group = page_owner_entity()) { + if ($group instanceof ElggGroup) + return true; + } + + return false; +} + + +/** + * Is the request from a known browser + * + * @return true/false + */ +function tp_is_person() { + $known = array('msie', 'mozilla', 'firefox', 'safari', 'webkit', 'opera', 'netscape', 'konqueror', 'gecko'); + + $agent = strtolower($_SERVER['HTTP_USER_AGENT']); + + foreach ($known as $browser) { + if (strpos($agent, $browser) !== false) { + return true; + } + } + + return false; +} diff --git a/plugins/tidypics/lib/watermark.php b/plugins/tidypics/lib/watermark.php new file mode 100644 index 0000000000000000000000000000000000000000..6b16f0e4ac771cb558b864cf30d19d024b94d85a --- /dev/null +++ b/plugins/tidypics/lib/watermark.php @@ -0,0 +1,193 @@ +<?php +/** + * Watermarking functions + * + * @package TidypicsWatermark + */ + +/** + * Make replacements in watermark text + * + * @param string $text + * @param ElggUser $owner + * @return string + */ +function tp_process_watermark_text($text, $owner) { + global $CONFIG; + + $text = str_replace("%name%", $owner->name, $text); + $text = str_replace("%sitename%", $CONFIG->sitename, $text); + + return $text; +} + +/** + * Create the watermark image filename + * + * @param string $text + * @param ElggUser $owner + * @return string + */ +function tp_get_watermark_filename($text, $owner) { + + $base = strtolower($text); + $base = preg_replace("/[^\w-]+/", "-", $base); + $base = trim($base, '-'); + + $filename = tp_get_img_dir(); + $filename .= strtolower($owner->username . "_" . $base . "_stamp"); + + return $filename; +} + +/** + * Use GD to apply watermark to image + * + * @param resource $image GD image resource + */ +function tp_gd_watermark($image) { + global $CONFIG; + + $watermark_text = get_plugin_setting('watermark_text', 'tidypics'); + if (!$watermark_text) { + return; + } + + // plugins can do their own watermark and return false to prevent this function from running + if (trigger_plugin_hook('tp_watermark', 'gd', $image, true) === false) { + return; + } + + $owner = get_loggedin_user(); + + $watermark_text = tp_process_watermark_text($watermark_text, $owner); + + // transparent gray + imagealphablending($image, true); + $textcolor = imagecolorallocatealpha($image, 50, 50, 50, 60); + + // font and location + $font = $CONFIG->pluginspath . "tidypics/fonts/LiberationSerif-Regular.ttf"; + $bbox = imagettfbbox(20, 0, $font, $watermark_text); + + $text_width = $bbox[2] - $bbox[0]; + $text_height = $bbox[1] - $bbox[7]; + + $image_width = imagesx($image); + $image_height = imagesy($image); + + $left = $image_width / 2 - $text_width / 2; + $top = $image_height - 20; + + // write the text on the image + imagettftext($image, 20, 0, $left, $top, $textcolor, $font, $watermark_text); +} + +/** + * imagick watermarking + * + * @param string $filename + * @return bool + */ +function tp_imagick_watermark($filename) { + + $watermark_text = get_plugin_setting('watermark_text', 'tidypics'); + if (!$watermark_text) { + return false; + } + + // plugins can do their own watermark and return false to prevent this function from running + if (trigger_plugin_hook('tp_watermark', 'imagick', $filename, true) === false) { + return true; + } + + $owner = get_loggedin_user(); + + $watermark_text = tp_process_watermark_text($watermark_text, $owner); + + $img = new Imagick($filename); + + $img->readImage($image); + + $draw = new ImagickDraw(); + + //$draw->setFont(""); + + $draw->setFontSize(28); + + $draw->setFillOpacity(0.5); + + $draw->setGravity(Imagick::GRAVITY_SOUTH); + + $img->annotateImage($draw, 0, 0, 0, $watermark_text); + + if ($img->writeImage($filename) != true) { + $img->destroy(); + return false; + } + + $img->destroy(); + + return true; +} + +/** + * ImageMagick watermarking + * + * @param string $filename + */ +function tp_im_cmdline_watermark($filename) { + + $watermark_text = get_plugin_setting('watermark_text', 'tidypics'); + if (!$watermark_text) { + return; + } + + // plugins can do their own watermark and return false to prevent this function from running + if (trigger_plugin_hook('tp_watermark', 'imagemagick', $filename, true) === false) { + return; + } + + $im_path = get_plugin_setting('im_path', 'tidypics'); + if (!$im_path) { + $im_path = "/usr/bin/"; + } + + // make sure end of path is / + if (substr($im_path, strlen($im_path)-1, 1) != "/") { + $im_path .= "/"; + } + + + $owner = get_loggedin_user(); + + $watermark_text = tp_process_watermark_text($watermark_text, $owner); + + $ext = ".png"; + + $user_stamp_base = tp_get_watermark_filename($watermark_text, $owner); + + + if ( !file_exists( $user_stamp_base . $ext )) { + //create the watermark image if it doesn't exist + $commands = array(); + $commands[] = $im_path . 'convert -size 300x50 xc:grey30 -pointsize 20 -gravity center -draw "fill grey70 text 0,0 \''. $watermark_text . '\'" "'. $user_stamp_base . '_fgnd' . $ext . '"'; + $commands[] = $im_path . 'convert -size 300x50 xc:black -pointsize 20 -gravity center -draw "fill white text 1,1 \''. $watermark_text . '\' text 0,0 \''. $watermark_text . '\' fill black text -1,-1 \''. $watermark_text . '\'" +matte ' . $user_stamp_base . '_mask' . $ext; + $commands[] = $im_path . 'composite -compose CopyOpacity "' . $user_stamp_base . "_mask" . $ext . '" "' . $user_stamp_base . '_fgnd' . $ext . '" "' . $user_stamp_base . $ext . '"'; + $commands[] = $im_path . 'mogrify -trim +repage "' . $user_stamp_base . $ext . '"'; + $commands[] = 'rm "' . $user_stamp_base . '_mask' . $ext . '"'; + $commands[] = 'rm "' . $user_stamp_base . '_fgnd' . $ext . '"'; + + foreach( $commands as $command ) { + exec( $command ); + } + } + + //apply the watermark + $commands = array(); + $commands[] = $im_path . 'composite -gravity south -geometry +0+10 "' . $user_stamp_base . $ext . '" "' . $filename . '" "' . $filename . '_watermarked"'; + $commands[] = "mv \"$filename" . "_watermarked\" \"$filename\""; + foreach( $commands as $command ) { + exec( $command ); + } +} diff --git a/plugins/tidypics/manifest.xml b/plugins/tidypics/manifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..d630e96017ccfec5b7217ba0adb5f5f4440bfb95 --- /dev/null +++ b/plugins/tidypics/manifest.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<plugin_manifest> + <field key="author" value="The Tidypics team" /> + <field key="version" value="1.6.8" /> + <field key="description" value="Tidypics Photo Gallery" /> + <field key="website" value="http://code.google.com/p/tidypics/" /> + <field key="copyright" value="2008-2010 Cash Costello and the Tidypics Team" /> + <field key="licence" value="GNU General Public License version 2" /> + <field key="elgg_version" value="2009022701" /> +</plugin_manifest> diff --git a/plugins/tidypics/mostvieweddashboard.php b/plugins/tidypics/mostvieweddashboard.php new file mode 100644 index 0000000000000000000000000000000000000000..5e7dc41c29a50e7a2da0d11c11e3ee9f29a03704 --- /dev/null +++ b/plugins/tidypics/mostvieweddashboard.php @@ -0,0 +1,44 @@ +<?php + + /** + * Tidypics full view of an image + * Given a GUID, this page will try and display any entity + * + */ + + // Load Elgg engine + include_once(dirname(dirname(dirname(__FILE__))) . "/engine/start.php"); + + global $CONFIG; + $prefix = $CONFIG->dbprefix; + $max = 24; + + //this works but is wildly inefficient + //$annotations = get_annotations(0, "object", "image", "tp_view", "", "", 5000); + + $sql = "SELECT ent.guid, count( * ) AS views + FROM " . $prefix . "entities ent + INNER JOIN " . $prefix . "entity_subtypes sub ON ent.subtype = sub.id + AND sub.subtype = 'image' + INNER JOIN " . $prefix . "annotations ann1 ON ann1.entity_guid = ent.guid + INNER JOIN " . $prefix . "metastrings ms ON ms.id = ann1.name_id + AND ms.string = 'tp_view' + GROUP BY ent.guid + ORDER BY views DESC + LIMIT $max"; + + $result = get_data($sql); + + $entities = array(); + foreach($result as $entity) { + $entities[] = get_entity($entity->guid); + } + + tidypics_mostviewed_submenus(); + + $title = elgg_echo("tidypics:mostvieweddashboard"); + $area2 = elgg_view_title($title); + $area2 .= elgg_view_entity_list($entities, $max, 0, $max); + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + page_draw($title, $body); +?> diff --git a/plugins/tidypics/pages/admin.php b/plugins/tidypics/pages/admin.php new file mode 100644 index 0000000000000000000000000000000000000000..437d2f47c0f6324263576e040529b2c2684b9f70 --- /dev/null +++ b/plugins/tidypics/pages/admin.php @@ -0,0 +1,24 @@ +<?php + /****************************************************************** + * + * Tidypics Admin Settings + * + *******************************************************************/ + + include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + + global $CONFIG; + + admin_gatekeeper(); + set_context('admin'); + set_page_owner($_SESSION['guid']); + + $tab = isset($_GET['tab']) ? $_GET['tab'] : 'settings'; + + $body = elgg_view_title(elgg_echo('tidypics:administration')); + + $body .= elgg_view("tidypics/admin/tidypics", array('tab' => $tab)); + + page_draw(elgg_echo('tidypics:administration'), elgg_view_layout("two_column_left_sidebar", '', $body)); + +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/download.php b/plugins/tidypics/pages/download.php new file mode 100644 index 0000000000000000000000000000000000000000..e4ad2e8556595b9403a1b087e84352f799fd6037 --- /dev/null +++ b/plugins/tidypics/pages/download.php @@ -0,0 +1,52 @@ +<?php + /** + * Tidypics Download Photos + * + * do not call this directly - call through page handler + */ + + global $CONFIG; + + $file_guid = (int) get_input("file_guid"); + $file = get_entity($file_guid); + + $type = get_input("type"); + + if ($file) { + $filename = $file->originalfilename; + $mime = $file->mimetype; + + header("Content-Type: $mime"); + if ($type == "inline") + header("Content-Disposition: inline; filename=\"$filename\""); + else + header("Content-Disposition: attachment; filename=\"$filename\""); + + + $readfile = new ElggFile($file_guid); + $readfile->owner_guid = $file->owner_guid; + + $contents = $readfile->grabFile(); + + if (empty($contents)) { + echo file_get_contents(dirname(dirname(__FILE__)) . "/graphics/image_error_large.png" ); + } else { + + // expires every 60 days + $expires = 60 * 60*60*24; + + header("Content-Length: " . strlen($contents)); + header("Cache-Control: public", true); + header("Pragma: public", true); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expires) . ' GMT', true); + + + echo $contents; + } + + exit; + } + else + register_error(elgg_echo("image:downloadfailed")); + +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/edit.php b/plugins/tidypics/pages/edit.php new file mode 100644 index 0000000000000000000000000000000000000000..abf1a0fdd5b3300967370830dc1f76b078ec270e --- /dev/null +++ b/plugins/tidypics/pages/edit.php @@ -0,0 +1,51 @@ +<?php + /** + * Tidypics Edit for Albums and Single Photos + * + */ + + include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + + // make sure the user is logged_in + gatekeeper(); + + set_context('photos'); + $guid = (int) get_input('guid'); + + if (!$entity = get_entity($guid)) + forward(); + + if (!$entity->canEdit()) + forward(); + + $subtype = $entity->getSubtype(); + + if ($subtype == 'album') { + $title = elgg_echo('album:edit'); + + if ($container = $entity->container_guid) + set_page_owner($container); + + } else if ($subtype == 'image') { + $title = elgg_echo('image:edit'); + + if ($container = get_entity($entity->container_guid)->container_guid) + set_page_owner($container); + + } else { + forward(); + } + + $page_owner = page_owner_entity(); + if ($page_owner instanceof ElggGroup) { + add_submenu_item( sprintf(elgg_echo('album:group'),$page_owner->name), + $CONFIG->wwwroot . "pg/photos/owned/" . $page_owner->username); + } + + + $area2 .= elgg_view_title($title); + $area2 .= elgg_view('tidypics/forms/edit', array('entity' => $entity, 'subtype' => $subtype)); + $body = elgg_view_layout('two_column_left_sidebar', $area1, $area2); + + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/edit_multiple.php b/plugins/tidypics/pages/edit_multiple.php new file mode 100644 index 0000000000000000000000000000000000000000..49b7dd6f373a948b9744a5bdca048b15e1f26dcb --- /dev/null +++ b/plugins/tidypics/pages/edit_multiple.php @@ -0,0 +1,47 @@ +<?php + /** + * Tidypics: Edit the properties of multiple images + * + * Called after upload only + */ + + include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + + gatekeeper(); + set_context('photos'); + + // parse out photo guids + $file_string = get_input('files'); + $file_array_sent = explode('-', $file_string); + $new_file_array = array(); + + // set owner of page based on first photo guid + $photo_guid = (int)$file_array_sent[0]; + $photo = get_entity($photo_guid); + + // set page owner based on owner of photo album + set_page_owner($photo->owner_guid); + $album = get_entity($photo->container_guid); + if ($album) { + $owner_guid = $album->container_guid; + if ($owner_guid) + set_page_owner($owner_guid); + } + + foreach ($file_array_sent as $file_guid) { + if ($entity = get_entity($file_guid)) { + if ($entity->canEdit()){ + array_push($new_file_array, $file_guid); + } + if (!$album_guid) + $album_guid = $entity->container_guid; + + } + } + + $title = elgg_echo('tidypics:editprops'); + $area2 .= elgg_view_title($title); + $area2 .= elgg_view("tidypics/forms/edit_multi", array('file_array' => $new_file_array, 'album_guid' => $album_guid)); + $body = elgg_view_layout('two_column_left_sidebar', $area1, $area2); + page_draw($title, $body); +?> diff --git a/plugins/tidypics/pages/flickr/importPhotosets.php b/plugins/tidypics/pages/flickr/importPhotosets.php new file mode 100644 index 0000000000000000000000000000000000000000..a807a0782f09004403c45832aa8971fde36db069 --- /dev/null +++ b/plugins/tidypics/pages/flickr/importPhotosets.php @@ -0,0 +1,50 @@ +<?php + + /** + * Import a set of photos from Flickr + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + $body = elgg_view_title( elgg_echo( 'flickr:importmanager' )); + $body .= "<h2>" . elgg_echo( 'flickr:desc' ) . "</h2>"; + + $viewer = get_loggedin_user(); + + require_once dirname(dirname(dirname(__FILE__))) . "/lib/phpFlickr/phpFlickr.php"; + require_once( dirname(dirname(dirname(__FILE__)))) . "/lib/flickr.php"; + $f = new phpFlickr("26b2abba37182aca62fe0eb2c7782050"); + + $viewer = get_loggedin_user(); + $flickr_username = get_metadata_byname( $viewer->guid, "flickr_username" ); + $flickr_id = get_metadata_byname( $viewer->guid, "flickr_id" ); + $album_id = get_metadata_byname( $viewer->guid, "flickr_album_id" ); + + if( intval( $album_id->value ) <= 0 ) { + register_error( sprintf( elgg_echo( 'flickr:errornoalbum' ), $album_id->value )); + forward( "/mod/tidypics/pages/flickr/setup.php" ); + } + + $photosets = $f->photosets_getList( $flickr_id->value ); + foreach( $photosets["photoset"] as $photoset ) { + $body .= "<div class='tidypics_album_images'>"; + $body .= "$photoset[title]<br />"; + + $count = 0; + $looper = 0; + //create links to import photos 10 at a time + while( $photoset["photos"] > $count ) { + $looper++; + $body .= " <a href='/mod/tidypics/actions/flickrImportPhotoset.php?set_id=$photoset[id]&page=$looper&album_id=$album_id->value'>$looper</a>"; + $count = $count + 10; + } + $body .= "<br />$photoset[photos] images"; + $body .= "</div>"; +// echo "<pre>"; var_dump( $photoset ); echo "</pre>"; die; + } + +// $body .= elgg_view("tidypics/forms/setupFlickr", array(), false, true ); + flickr_menu(); + page_draw( elgg_echo( 'flickr:importmanager' ), elgg_view_layout("two_column_left_sidebar", '', $body)); + +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/flickr/setup.php b/plugins/tidypics/pages/flickr/setup.php new file mode 100644 index 0000000000000000000000000000000000000000..1de8c29c2c399a49d8e5f96b4336d70ca06baf3c --- /dev/null +++ b/plugins/tidypics/pages/flickr/setup.php @@ -0,0 +1,17 @@ +<?php + + /** + * Setup a users Flickr username + * + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + + $viewer = get_loggedin_user(); + + $body = elgg_view_title( elgg_echo( 'flickr:setup') ); + $body .= elgg_view("tidypics/forms/setupFlickr", array(), false, true ); +// echo "<pre>"; var_dump($body); echo "</pre>"; + page_draw( elgg_echo( 'flickr:setup'), elgg_view_layout("two_column_left_sidebar", '', $body)); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/friends.php b/plugins/tidypics/pages/friends.php new file mode 100644 index 0000000000000000000000000000000000000000..03ae1300ac022b6e5eb8510b49a9cb53d37e6951 --- /dev/null +++ b/plugins/tidypics/pages/friends.php @@ -0,0 +1,41 @@ +<?php + /** + * Tidypics Friends Albums Listing + * + * List all the albums of someone's friends + */ + + include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + + $username = get_input('username'); + + // if no username, redirect to world photo albums + if (!$username) { + forward('pg/photos/world'); + } + + // setup title + $user = get_user_by_username($username); + if (!$user) { + forward('pg/photos/world'); + } + if ($user->guid == get_loggedin_userid()) + $title = elgg_echo('album:yours:friends'); + else + $title = sprintf(elgg_echo('album:friends'), $user->name); + + $area2 = elgg_view_title($title); + + $albums = get_user_friends_objects($user->guid, 'album', 12); + + // get html for viewing list of photo albums + set_context('search'); + set_input('search_viewtype', 'gallery'); // need to force gallery view + $content = tp_view_entity_list($albums, count($albums), 0, 12, false, false, true); + + $area2 = elgg_view('tidypics/content_wrapper', array('title' => $title, 'content' => $content,)); + + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/lists/flickr.php b/plugins/tidypics/pages/lists/flickr.php new file mode 100644 index 0000000000000000000000000000000000000000..b9886042bf2bfbaf8908020807cb42c6b8872a8e --- /dev/null +++ b/plugins/tidypics/pages/lists/flickr.php @@ -0,0 +1,60 @@ +<?php +require_once dirname(dirname(dirname(__FILE__))) . "/lib/phpFlickr/phpFlickr.php"; +$f = new phpFlickr("26b2abba37182aca62fe0eb2c7782050"); + +// Load Elgg engine +include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + +$username = get_input('username'); +if( !empty( $username )) { + $temp_user = get_user_by_username( $username ); +} else { + $temp_user = get_loggedin_user(); +} +$flickr_username = get_metadata_byname( $temp_user->guid, "flickr_username" ); +if( empty( $flickr_username )) { + register_error( "No Flickr username set"); + echo "<pre>No flickr username set: $temp_user->guid"; die; + forward( "/" ); + die; +} +$flickr_user = $f->people_findByUsername( $flickr_username->value ); + +// Get the friendly URL of the user's photos +$photos_url = $f->urls_getUserPhotos( $flickr_user["id"] ); + +if( !empty( $flickr_user )) { + $recent = $f->people_getPublicPhotos( $flickr_user['id'], NULL, NULL, 5 ); +} else { + echo "user not found"; die; +} +//echo "<pre>"; var_dump( $recent ); echo "</pre>"; + +//echo "<pre>"; var_dump( $user ); echo "</pre>"; +$body = elgg_view_title( "Flickr photos for $flickr_user[username]" ); + +$count = 0; +foreach ($recent['photos']['photo'] as $photo) { + + $photo_info = $f->photos_getInfo( $photo["id"], $photo["secret"] ); + $body .= "<div class='tidypics_album_images'>"; + $body .= "$photo_info[title]<br />Views: $photo_info[views]<br />"; + $body .= "<a href=$photos_url$photo[id]>"; + $body .= "<img border='0' alt='$photo[title]' ". + "src=" . $f->buildPhotoURL($photo, "Square") . ">"; + $body .= "</a>"; + + $tag_count = 0; + $body .= "<br /><div style='font-size: 8px;'>Tags:<br />"; + foreach( $photo_info["tags"]["tag"] as $tag ) { + if( $tag_count ) $body .= ", "; + $body .= "$tag[_content]"; + $tag_count++; + } + + $body .= "</div></div>"; + $count++; +} +page_draw( "Flickr photos for $flickr_user[username]", elgg_view_layout("two_column_left_sidebar", '', $body)); + +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/lists/highestrated.php b/plugins/tidypics/pages/lists/highestrated.php new file mode 100644 index 0000000000000000000000000000000000000000..e05e7a9baf50562ce6c61894164f9ed931877fa6 --- /dev/null +++ b/plugins/tidypics/pages/lists/highestrated.php @@ -0,0 +1,65 @@ +<?php + /** + * Tidypics Friends Albums Listing + * + */ + + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + + //if no friends were requested, see world pictures instead, or redirect to user's friends +/* if (is_null(get_input('username')) || get_input('username')=='') { + if (!isloggedin()) { + forward('pg/photos/world'); + } else { + forward('pg/photos/friends/' . $_SESSION['user']->username); + } + }*/ + +// if (is_null(page_owner_entity()->name) || page_owner_entity()->name == '') { +// $groupname = get_input('username'); +// } else { +// $groupname = page_owner_entity()->name; +// }; +// + //there has to be a better way to do this + if(!$groupname) { + $page = get_input("page"); + list($pagename, $groupname) = split("/", $page); + } + + list($group_holder, $album_id) = split(":", $groupname); +// echo "<pre>page: $page\ngroup: $groupname\nalbum: $album_id"; die; + + $user = get_user_by_username($friendname); + global $CONFIG; + $prefix = $CONFIG->dbprefix; + $max = 24; + + $sql = "SELECT ent.guid, count(1) as mycount, avg(ms2.string) as average + FROM " . $prefix . "entities ent + INNER JOIN " . $prefix . "entity_subtypes sub ON ent.subtype = sub.id + AND sub.subtype = 'image' AND ent.container_guid = $album_id + INNER JOIN " . $prefix . "annotations ann1 ON ann1.entity_guid = ent.guid + INNER JOIN " . $prefix . "metastrings ms ON ms.id = ann1.name_id + AND ms.string = 'generic_rate' + INNER JOIN " . $prefix . "metastrings ms2 ON ms2.id = ann1.value_id + INNER JOIN " . $prefix . "users_entity u ON ann1.owner_guid = u.guid + GROUP BY ent.guid HAVING mycount > 1 + ORDER BY average DESC + LIMIT $max"; + + $result = get_data($sql); + + $entities = array(); + foreach($result as $entity) { + $entities[] = get_entity($entity->guid); + } + + $album = get_entity($album_id); + $title = $album["title"] . ": " . elgg_echo("tidypics:highestrated"); + $area2 = elgg_view_title($title); + $area2 .= elgg_view_entity_list($entities, $max, 0, $max, false); + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + page_draw($title, $body); + +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/lists/highestvotecount.php b/plugins/tidypics/pages/lists/highestvotecount.php new file mode 100644 index 0000000000000000000000000000000000000000..26b90714457cb47350d075ffcc9d6a542280c2f1 --- /dev/null +++ b/plugins/tidypics/pages/lists/highestvotecount.php @@ -0,0 +1,50 @@ +<?php + + /** + * Tidypics full view of an image + * Given a GUID, this page will try and display any entity + * + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + + global $CONFIG; + $prefix = $CONFIG->dbprefix; + $max = 24; + + $sql = "SELECT ent.guid, u.name as owner, count( 1 ) AS mycount, avg( ms2.string ) AS average + FROM " . $prefix . "entities ent + INNER JOIN " . $prefix . "entity_subtypes sub ON ent.subtype = sub.id + AND sub.subtype = 'image' + INNER JOIN " . $prefix . "annotations ann1 ON ann1.entity_guid = ent.guid + INNER JOIN " . $prefix . "metastrings ms ON ms.id = ann1.name_id + AND ms.string = 'generic_rate' + INNER JOIN " . $prefix . "metastrings ms2 ON ms2.id = ann1.value_id + INNER JOIN " . $prefix . "users_entity u ON ent.owner_guid = u.guid + GROUP BY ent.guid + ORDER BY mycount DESC + LIMIT $max"; + + $result = get_data($sql); + + $title = "Most voted images"; + $area2 = elgg_view_title($title); + + $entities = array(); + foreach($result as $entity) { + $entities[] = get_entity($entity->guid); + $full_entity = get_entity($entity->guid); + $area2 .= " <div class='tidypics_album_images'> + Owner: $entity->owner<br /> + Votes: $entity->mycount<br /> + Average: $entity->average + </div> + "; + $area2 .= elgg_view_entity($full_entity); + + } + + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/lists/mostcommentedimages.php b/plugins/tidypics/pages/lists/mostcommentedimages.php new file mode 100644 index 0000000000000000000000000000000000000000..801409fdc0946056a65a5064e71d8d7fe16cc1b3 --- /dev/null +++ b/plugins/tidypics/pages/lists/mostcommentedimages.php @@ -0,0 +1,43 @@ +<?php + + /** + * Tidypics full view of an image + * Given a GUID, this page will try and display any entity + * + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + + global $CONFIG; + $prefix = $CONFIG->dbprefix; + $max = 24; + + //this works but is wildly inefficient + //$annotations = get_annotations(0, "object", "image", "tp_view", "", "", 5000); + + $sql = "SELECT ent.guid, count( * ) AS views + FROM " . $prefix . "entities ent + INNER JOIN " . $prefix . "entity_subtypes sub ON ent.subtype = sub.id + AND sub.subtype = 'image' + INNER JOIN " . $prefix . "annotations ann1 ON ann1.entity_guid = ent.guid + INNER JOIN " . $prefix . "metastrings ms ON ms.id = ann1.name_id + AND ms.string = 'generic_comment' + GROUP BY ent.guid + ORDER BY views DESC + LIMIT $max"; + + $result = get_data($sql); + + $entities = array(); + foreach($result as $entity) { + $entities[] = get_entity($entity->guid); + } + + tidypics_mostviewed_submenus(); + $title = elgg_echo("tidypics:mostcommented"); + $area2 = elgg_view_title($title); + $area2 .= elgg_view_entity_list($entities, $max, 0, $max, false); + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/lists/mostcommentedimagesthismonth.php b/plugins/tidypics/pages/lists/mostcommentedimagesthismonth.php new file mode 100644 index 0000000000000000000000000000000000000000..d95e2aff55bb518839eae163275b9df714abedbe --- /dev/null +++ b/plugins/tidypics/pages/lists/mostcommentedimagesthismonth.php @@ -0,0 +1,50 @@ +<?php + + /** + * Tidypics full view of an image + * Given a GUID, this page will try and display any entity + * + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + + global $CONFIG; + $prefix = $CONFIG->dbprefix; + $max = 24; + + + //find timestamps for first and last days of this month + $time_info = new stdClass(); + $time_info->start = mktime(0,0,0, date("m"), 1, date("Y")); + $time_info->end = mktime(); + + //this works but is wildly inefficient + //$annotations = get_annotations(0, "object", "image", "tp_view", "", "", 5000); + + $sql = "SELECT ent.guid, count( * ) AS views + FROM " . $prefix . "entities ent + INNER JOIN " . $prefix . "entity_subtypes sub ON ent.subtype = sub.id + AND sub.subtype = 'image' + INNER JOIN " . $prefix . "annotations ann1 ON ann1.entity_guid = ent.guid + INNER JOIN " . $prefix . "metastrings ms ON ms.id = ann1.name_id + AND ms.string = 'generic_comment' + WHERE ann1.time_created BETWEEN $time_info->start AND $time_info->end + GROUP BY ent.guid + ORDER BY views DESC + LIMIT $max"; + + $result = get_data($sql); + + $entities = array(); + foreach($result as $entity) { + $entities[] = get_entity($entity->guid); + } + + tidypics_mostviewed_submenus(); + $title = elgg_echo("tidypics:mostcommentedthismonth"); + $area2 = elgg_view_title($title); + $area2 .= elgg_view_entity_list($entities, $max, 0, $max, false); + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/lists/mostcommentedimagestoday.php b/plugins/tidypics/pages/lists/mostcommentedimagestoday.php new file mode 100644 index 0000000000000000000000000000000000000000..bd1a0cbec236bd12e75004d27327a2b61a03f0cc --- /dev/null +++ b/plugins/tidypics/pages/lists/mostcommentedimagestoday.php @@ -0,0 +1,50 @@ +<?php + + /** + * Tidypics full view of an image + * Given a GUID, this page will try and display any entity + * + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + + global $CONFIG; + $prefix = $CONFIG->dbprefix; + $max = 24; + + + //find timestamps for today + $time_info = new stdClass(); + $time_info->start = mktime(0,0,0, date("m"), date("d"), date("Y")); + $time_info->end = mktime(); + + //this works but is wildly inefficient + //$annotations = get_annotations(0, "object", "image", "tp_view", "", "", 5000); + + $sql = "SELECT ent.guid, count( * ) AS views + FROM " . $prefix . "entities ent + INNER JOIN " . $prefix . "entity_subtypes sub ON ent.subtype = sub.id + AND sub.subtype = 'image' + INNER JOIN " . $prefix . "annotations ann1 ON ann1.entity_guid = ent.guid + INNER JOIN " . $prefix . "metastrings ms ON ms.id = ann1.name_id + AND ms.string = 'generic_comment' + WHERE ann1.time_created BETWEEN $time_info->start AND $time_info->end + GROUP BY ent.guid + ORDER BY views DESC + LIMIT $max"; + + $result = get_data($sql); + + $entities = array(); + foreach($result as $entity) { + $entities[] = get_entity($entity->guid); + } + + tidypics_mostviewed_submenus(); + $title = elgg_echo("tidypics:mostcommentedtoday"); + $area2 = elgg_view_title($title); + $area2 .= elgg_view_entity_list($entities, $max, 0, $max, false); + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/lists/mostrecentimages.php b/plugins/tidypics/pages/lists/mostrecentimages.php new file mode 100644 index 0000000000000000000000000000000000000000..178e3c722b32aaecc3d31521e8ccf4d12edfbeaa --- /dev/null +++ b/plugins/tidypics/pages/lists/mostrecentimages.php @@ -0,0 +1,56 @@ +<?php + + /** + * Most recently uploaded images - individual or world + * + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + + // start with assumption this is for all site photos + $title = elgg_echo('tidypics:mostrecent'); + $user_id = 0; + + // is this all site or an individuals images + $username = get_input('username'); + if ($username) { + $user = get_user_by_username($username); + if ($user) { + $user_id = $user->guid; + + if ($user_id == get_loggedin_userid()) + $title = elgg_echo('tidypics:yourmostrecent'); + else + $title = sprintf(elgg_echo("tidypics:friendmostrecent"), $user->name); + } + } else { + // world view - set page owner to logged in user + if (isloggedin()) { + set_page_owner(get_loggedin_userid()); + } + } + + // allow other plugins to override the slideshow + $slideshow_link = trigger_plugin_hook('tp_slideshow', 'album', array(), null); + if ($slideshow_link) { + add_submenu_item(elgg_echo('album:slideshow'), + $slideshow_link, + 'photos' ); + } + + // how many do we display + $max = 12; + + // grab the html to display the images + $images = tp_list_entities("object", "image", $user_id, null, $max, false, false, true); + + + // this view takes care of the title on the main column and the content wrapper + $area2 = elgg_view('tidypics/content_wrapper', array('title' => $title, 'content' => $images,)); + if( empty( $area2 )) $area2 = $images; + + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/lists/mostviewedimages.php b/plugins/tidypics/pages/lists/mostviewedimages.php new file mode 100644 index 0000000000000000000000000000000000000000..d945680f1033a8711df47566e5d67ae67efd6507 --- /dev/null +++ b/plugins/tidypics/pages/lists/mostviewedimages.php @@ -0,0 +1,86 @@ +<?php + + /** + * Most viewed images - either for a user or all site + * + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + + global $CONFIG; + $prefix = $CONFIG->dbprefix; + $max = 24; + + $owner_guid = page_owner(); + + //$start = microtime(true); + $photos = tp_get_entities_from_annotations_calculate_x( + 'count', + 'object', + 'image', + 'tp_view', + '', + '', + $owner_guid, + $max); + //error_log("elgg query is " . (float)(microtime(true) - $start)); + + //this works but is wildly inefficient + //$annotations = get_annotations(0, "object", "image", "tp_view", "", "", 5000); +/* + $start = microtime(true); + $sql = "SELECT ent.guid, count( * ) AS views + FROM " . $prefix . "entities ent + INNER JOIN " . $prefix . "entity_subtypes sub ON ent.subtype = sub.id + AND sub.subtype = 'image' + INNER JOIN " . $prefix . "annotations ann1 ON ann1.entity_guid = ent.guid AND ann1.owner_guid != ent.owner_guid + INNER JOIN " . $prefix . "metastrings ms ON ms.id = ann1.name_id + AND ms.string = 'tp_view' + GROUP BY ent.guid + ORDER BY views DESC + LIMIT $max"; + + $result = get_data($sql); + + $entities = array(); + foreach($result as $entity) { + $entities[] = get_entity($entity->guid); + } +*/ + //error_log("custom query is " . (float)(microtime(true) - $start)); + + // allow other plugins to override the slideshow + $slideshow_link = trigger_plugin_hook('tp_slideshow', 'album', array(), null); + if ($slideshow_link) { + add_submenu_item(elgg_echo('album:slideshow'), + $slideshow_link, + 'photos' ); + } + + if ($owner_guid) { + if ($owner_guid == get_loggedin_userid()) { + $title = elgg_echo("tidypics:yourmostviewed"); + } else { + $title = sprintf(elgg_echo("tidypics:friendmostviewed"), page_owner_entity()->name); + } + } else { + // world view - set page owner to logged in user + if (isloggedin()) { + set_page_owner(get_loggedin_userid()); + } + + $title = elgg_echo("tidypics:mostviewed"); + } + $area2 = elgg_view_title($title); + + // grab the html to display the images + $content = tp_view_entity_list($photos, $max, 0, $max, false); + + // this view takes care of the title on the main column and the content wrapper + $area2 = elgg_view('tidypics/content_wrapper', array('title' => $title, 'content' => $content,)); + if( empty( $area2 )) $area2 = $content; + + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/lists/mostviewedimageslastmonth.php b/plugins/tidypics/pages/lists/mostviewedimageslastmonth.php new file mode 100644 index 0000000000000000000000000000000000000000..1ed9161f7ca0f5c82b8497e68d71c7eb33b2a121 --- /dev/null +++ b/plugins/tidypics/pages/lists/mostviewedimageslastmonth.php @@ -0,0 +1,50 @@ +<?php + + /** + * Tidypics full view of an image + * Given a GUID, this page will try and display any entity + * + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + + global $CONFIG; + $prefix = $CONFIG->dbprefix; + $max = 24; + + + //find timestamps for first and last days of last month + $time_info = new stdClass(); + $time_info->start = strtotime("-1 months", mktime(0,0,0, date("m"), 1, date("Y"))); + $time_info->end = mktime(0,0,0,date("m"), 0, date("Y")); + + //this works but is wildly inefficient + //$annotations = get_annotations(0, "object", "image", "tp_view", "", "", 5000); + + $sql = "SELECT ent.guid, count( * ) AS views + FROM " . $prefix . "entities ent + INNER JOIN " . $prefix . "entity_subtypes sub ON ent.subtype = sub.id + AND sub.subtype = 'image' + INNER JOIN " . $prefix . "annotations ann1 ON ann1.entity_guid = ent.guid AND ann1.owner_guid != ent.owner_guid + INNER JOIN " . $prefix . "metastrings ms ON ms.id = ann1.name_id + AND ms.string = 'tp_view' + WHERE ann1.time_created BETWEEN $time_info->start AND $time_info->end + GROUP BY ent.guid + ORDER BY views DESC + LIMIT $max"; + + $result = get_data($sql); + + $entities = array(); + foreach($result as $entity) { + $entities[] = get_entity($entity->guid); + } + + tidypics_mostviewed_submenus(); + $title = elgg_echo("tidypics:mostviewedlastmonth"); + $area2 = elgg_view_title($title); + $area2 .= elgg_view_entity_list($entities, $max, 0, $max, false); + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/lists/mostviewedimagesthismonth.php b/plugins/tidypics/pages/lists/mostviewedimagesthismonth.php new file mode 100644 index 0000000000000000000000000000000000000000..bfe08e1da25bb705b0d87accd4d4fab17b42ee35 --- /dev/null +++ b/plugins/tidypics/pages/lists/mostviewedimagesthismonth.php @@ -0,0 +1,50 @@ +<?php + + /** + * Tidypics full view of an image + * Given a GUID, this page will try and display any entity + * + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + + global $CONFIG; + $prefix = $CONFIG->dbprefix; + $max = 24; + + + //find timestamps for first and last days of this month + $time_info = new stdClass(); + $time_info->start = mktime(0,0,0, date("m"), 1, date("Y")); + $time_info->end = mktime(); + + //this works but is wildly inefficient + //$annotations = get_annotations(0, "object", "image", "tp_view", "", "", 5000); + + $sql = "SELECT ent.guid, count( * ) AS views + FROM " . $prefix . "entities ent + INNER JOIN " . $prefix . "entity_subtypes sub ON ent.subtype = sub.id + AND sub.subtype = 'image' + INNER JOIN " . $prefix . "annotations ann1 ON ann1.entity_guid = ent.guid AND ann1.owner_guid != ent.owner_guid + INNER JOIN " . $prefix . "metastrings ms ON ms.id = ann1.name_id + AND ms.string = 'tp_view' + WHERE ann1.time_created BETWEEN $time_info->start AND $time_info->end + GROUP BY ent.guid + ORDER BY views DESC + LIMIT $max"; + + $result = get_data($sql); + + $entities = array(); + foreach($result as $entity) { + $entities[] = get_entity($entity->guid); + } + + tidypics_mostviewed_submenus(); + $title = elgg_echo("tidypics:mostviewedthismonth"); + $area2 = elgg_view_title($title); + $area2 .= elgg_view_entity_list($entities, $max, 0, $max, false); + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/lists/mostviewedimagesthisyear.php b/plugins/tidypics/pages/lists/mostviewedimagesthisyear.php new file mode 100644 index 0000000000000000000000000000000000000000..fe1a63d38b2e9df7e62927c75a9ea7019e85d5fa --- /dev/null +++ b/plugins/tidypics/pages/lists/mostviewedimagesthisyear.php @@ -0,0 +1,50 @@ +<?php + + /** + * Tidypics full view of an image + * Given a GUID, this page will try and display any entity + * + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + + global $CONFIG; + $prefix = $CONFIG->dbprefix; + $max = 24; + + + //find timestamps for first day of the year and current date + $time_info = new stdClass(); + $time_info->start = mktime(0,0,0, 1, 1, date("Y")); + $time_info->end = mktime(); + + //this works but is wildly inefficient + //$annotations = get_annotations(0, "object", "image", "tp_view", "", "", 5000); + + $sql = "SELECT ent.guid, count( * ) AS views + FROM " . $prefix . "entities ent + INNER JOIN " . $prefix . "entity_subtypes sub ON ent.subtype = sub.id + AND sub.subtype = 'image' + INNER JOIN " . $prefix . "annotations ann1 ON ann1.entity_guid = ent.guid AND ann1.owner_guid != ent.owner_guid + INNER JOIN " . $prefix . "metastrings ms ON ms.id = ann1.name_id + AND ms.string = 'tp_view' + WHERE ann1.time_created BETWEEN $time_info->start AND $time_info->end + GROUP BY ent.guid + ORDER BY views DESC + LIMIT $max"; + + $result = get_data($sql); + + $entities = array(); + foreach($result as $entity) { + $entities[] = get_entity($entity->guid); + } + + tidypics_mostviewed_submenus(); + $title = elgg_echo("tidypics:mostviewedthisyear"); + $area2 = elgg_view_title($title); + $area2 .= elgg_view_entity_list($entities, $max, 0, $max, false); + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/lists/mostviewedimagestoday.php b/plugins/tidypics/pages/lists/mostviewedimagestoday.php new file mode 100644 index 0000000000000000000000000000000000000000..f8e84475363e3b2ff74d15c969634cc5f518324a --- /dev/null +++ b/plugins/tidypics/pages/lists/mostviewedimagestoday.php @@ -0,0 +1,50 @@ +<?php + + /** + * Tidypics full view of an image + * Given a GUID, this page will try and display any entity + * + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + + global $CONFIG; + $prefix = $CONFIG->dbprefix; + $max = 24; + + + //find timestamps for today + $time_info = new stdClass(); + $time_info->start = mktime(0,0,0, date("m"), date("d"), date("Y")); + $time_info->end = mktime(); + + //this works but is wildly inefficient + //$annotations = get_annotations(0, "object", "image", "tp_view", "", "", 5000); + + $sql = "SELECT ent.guid, count( * ) AS views + FROM " . $prefix . "entities ent + INNER JOIN " . $prefix . "entity_subtypes sub ON ent.subtype = sub.id + AND sub.subtype = 'image' + INNER JOIN " . $prefix . "annotations ann1 ON ann1.entity_guid = ent.guid AND ann1.owner_guid != ent.owner_guid + INNER JOIN " . $prefix . "metastrings ms ON ms.id = ann1.name_id + AND ms.string = 'tp_view' + WHERE ann1.time_created BETWEEN $time_info->start AND $time_info->end + GROUP BY ent.guid + ORDER BY views DESC + LIMIT $max"; + + $result = get_data($sql); + + $entities = array(); + foreach($result as $entity) { + $entities[] = get_entity($entity->guid); + } + + tidypics_mostviewed_submenus(); + $title = elgg_echo("tidypics:mostviewedtoday"); + $area2 = elgg_view_title($title); + $area2 .= elgg_view_entity_list($entities, $max, 0, $max, false); + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/lists/recentlycommented.php b/plugins/tidypics/pages/lists/recentlycommented.php new file mode 100644 index 0000000000000000000000000000000000000000..1d5f7aea7598dd8fbe3578631e52e2633164d118 --- /dev/null +++ b/plugins/tidypics/pages/lists/recentlycommented.php @@ -0,0 +1,72 @@ +<?php + + /** + * Images recently commented on - world view only + * + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + + // world view - set page owner to logged in user + if (isloggedin()) { + set_page_owner(get_loggedin_userid()); + } + + // allow other plugins to override the slideshow + $slideshow_link = trigger_plugin_hook('tp_slideshow', 'album', array(), null); + if ($slideshow_link) { + add_submenu_item(elgg_echo('album:slideshow'), + $slideshow_link, + 'photos' ); + } + + + global $CONFIG; + $prefix = $CONFIG->dbprefix; + $max_limit = 200; //get extra because you'll have multiple views per image in the result set + $max = 16; //controls how many actually show on screen + + //this works but is wildly inefficient + //$annotations = get_annotations(0, "object", "image", "tp_view", "", "", 5000); + + $sql = "SELECT distinct (ent.guid), ann1.time_created + FROM " . $prefix . "entities ent + INNER JOIN " . $prefix . "entity_subtypes sub ON ent.subtype = sub.id + AND sub.subtype = 'image' + INNER JOIN " . $prefix . "annotations ann1 ON ann1.entity_guid = ent.guid + INNER JOIN " . $prefix . "metastrings ms ON ms.id = ann1.name_id + AND ms.string = 'generic_comment' + ORDER BY ann1.time_created DESC + LIMIT $max_limit"; + + $result = get_data($sql); + + $entities = array(); + foreach($result as $entity) { + if(!$entities[$entity->guid]) { + $entities[$entity->guid] = get_entity($entity->guid); + } + if(count($entities) >= $max) break; + } + + $user = get_loggedin_user(); + if( $user->guid == 9 ) { + echo "<pre>"; + var_dump( $sql); +// var_dump( $result ); + echo "</pre>"; + } + $title = elgg_echo("tidypics:recentlycommented"); + $area2 = elgg_view_title($title); + + // grab the html to display the images + $images = tp_view_entity_list($entities, $max, 0, $max, false); + + // this view takes care of the title on the main column and the content wrapper + $area2 = elgg_view('tidypics/content_wrapper', array('title' => $title, 'content' => $images,)); + if( empty( $area2 )) $area2 = $images; + + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/lists/recentlyviewed.php b/plugins/tidypics/pages/lists/recentlyviewed.php new file mode 100644 index 0000000000000000000000000000000000000000..16ad474df6e76806b4e474de23198df6ec07443c --- /dev/null +++ b/plugins/tidypics/pages/lists/recentlyviewed.php @@ -0,0 +1,65 @@ +<?php + + /** + * Most recently viewed images - world view only right now + * + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + + // world view - set page owner to logged in user + if (isloggedin()) { + set_page_owner(get_loggedin_userid()); + } + + // allow other plugins to override the slideshow + $slideshow_link = trigger_plugin_hook('tp_slideshow', 'album', array(), null); + if ($slideshow_link) { + add_submenu_item(elgg_echo('album:slideshow'), + $slideshow_link, + 'photos' ); + } + + + global $CONFIG; + $prefix = $CONFIG->dbprefix; + $max_limit = 200; //get extra because you'll have multiple views per image in the result set + $max = 16; //controls how many actually show on screen + + //this works but is wildly inefficient + //$annotations = get_annotations(0, "object", "image", "tp_view", "", "", 5000); + + $sql = "SELECT distinct ent.guid, ann1.time_created + FROM " . $prefix . "entities ent + INNER JOIN " . $prefix . "entity_subtypes sub ON ent.subtype = sub.id + AND sub.subtype = 'image' + INNER JOIN " . $prefix . "annotations ann1 ON ann1.entity_guid = ent.guid + INNER JOIN " . $prefix . "metastrings ms ON ms.id = ann1.name_id + AND ms.string = 'tp_view' + ORDER BY ann1.id DESC + LIMIT $max_limit"; + + $result = get_data($sql); + + $entities = array(); + foreach($result as $entity) { + if(!$entities[$entity->guid]) { + $entities[$entity->guid] = get_entity($entity->guid); + } + if(count($entities) >= $max) break; + } + + $title = elgg_echo("tidypics:recentlyviewed"); + $area2 = elgg_view_title($title); + + // grab the html to display the images + $images = tp_view_entity_list($entities, $max, 0, $max, false); + + // this view takes care of the title on the main column and the content wrapper + $area2 = elgg_view('tidypics/content_wrapper', array('title' => $title, 'content' => $images,)); + if( empty( $area2 )) $area2 = $images; + + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/lists/recentvotes.php b/plugins/tidypics/pages/lists/recentvotes.php new file mode 100644 index 0000000000000000000000000000000000000000..3d8eac97e6fdf61a92d48af26c4ea8a867d34f6f --- /dev/null +++ b/plugins/tidypics/pages/lists/recentvotes.php @@ -0,0 +1,52 @@ +<?php + + /** + * Tidypics full view of an image + * Given a GUID, this page will try and display any entity + * + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . "/engine/start.php"; + + global $CONFIG; + $prefix = $CONFIG->dbprefix; + $max = 24; + + $sql = "SELECT ent.guid, u2.name AS owner, u.name AS voter, ms2.string as vote + FROM " . $prefix . "entities ent + INNER JOIN " . $prefix . "entity_subtypes sub ON ent.subtype = sub.id + AND sub.subtype = 'image' + INNER JOIN " . $prefix . "annotations ann1 ON ann1.entity_guid = ent.guid + INNER JOIN " . $prefix . "metastrings ms ON ms.id = ann1.name_id + AND ms.string = 'generic_rate' + INNER JOIN " . $prefix . "metastrings ms2 ON ms2.id = ann1.value_id + INNER JOIN " . $prefix . "users_entity u ON ann1.owner_guid = u.guid + INNER JOIN " . $prefix . "users_entity u2 ON ent.owner_guid = u2.guid + ORDER BY ann1.time_created DESC + LIMIT $max"; + + $result = get_data($sql); + + $title = "Recently rated images"; + $area2 = elgg_view_title($title); + + $entities = array(); + foreach($result as $entity) { + $entities[] = get_entity($entity->guid); + $full_entity = get_entity($entity->guid); + $area2 .= " <div class='tidypics_album_images'> + Owner: $entity->owner<br /> + Voter: $entity->voter<br /> + Rating: $entity->vote + </div> + "; + $area2 .= elgg_view_entity($full_entity); + + } + + +// $area2 .= elgg_view_entity_list($entities, $max, 0, $max); + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/newalbum.php b/plugins/tidypics/pages/newalbum.php new file mode 100644 index 0000000000000000000000000000000000000000..fda886d52df2cdd19c568aa20f11b879c6301559 --- /dev/null +++ b/plugins/tidypics/pages/newalbum.php @@ -0,0 +1,32 @@ +<?php + + /** + * Tidypics Create New Album Page + * + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + + // must be logged in to create a new album + gatekeeper(); + + // Get the current page's owner + $page_owner = page_owner_entity(); + if ($page_owner === false || is_null($page_owner)) { + $page_owner = $_SESSION['user']; + set_page_owner($_SESSION['guid']); + } + + if ($page_owner instanceof ElggGroup) { + add_submenu_item( sprintf(elgg_echo('album:group'),$page_owner->name), + $CONFIG->wwwroot . "pg/photos/owned/" . $page_owner->username); + } + + $area2 = elgg_view_title(elgg_echo('album:add')); + $area2 .= elgg_view("tidypics/forms/edit"); + + // Display page + page_draw(elgg_echo('album:add'),elgg_view_layout("two_column_left_sidebar", $area1, $area2, $area3 )); + +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/ownedalbums.php b/plugins/tidypics/pages/ownedalbums.php new file mode 100644 index 0000000000000000000000000000000000000000..d22c6d44ab785e3fab12339ad57d8be21f19c6f9 --- /dev/null +++ b/plugins/tidypics/pages/ownedalbums.php @@ -0,0 +1,53 @@ +<?php + /** + * tidypics photo gallery album listing page for a person/group + * + * Shows all the albums that belong to that person or group + */ + + include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + + // if this page belongs to a closed group, prevent anyone outside group from seeing + if (is_callable('group_gatekeeper')) group_gatekeeper(); + + //get the owner of the current page + $owner = page_owner_entity(); + + + //if page owner cannot be found, forward to world album list + if (is_null($owner->username) || empty($owner->username)) { + forward('pg/photos/world'); + } + + + // setup group menu for album index + if ($owner instanceof ElggGroup) { + add_submenu_item( sprintf(elgg_echo('album:group'),$owner->name), + $CONFIG->wwwroot . "pg/photos/owned/" . $owner->username); + if (can_write_to_container(0, $owner->guid)) { + add_submenu_item( elgg_echo('album:create'), + $CONFIG->wwwroot . 'pg/photos/new/' . $owner->username, + 'tidypics'); + } + } + + //set the title + $title = sprintf(elgg_echo('album:user'), $owner->name); + $area2 = elgg_view_title($title); + + // Get objects + set_context('search'); + set_input('search_viewtype', 'gallery'); + if ($owner instanceof ElggGroup) + $content .= tp_list_entities("object", "album", 0, $owner->guid, 12, false); + else + $content .= tp_list_entities("object", "album", $owner->guid, $owner->guid, 12, false); + + $area2 = elgg_view('tidypics/content_wrapper', array('title' => $title, 'content' => $content,)); + + set_context('photos'); + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + + // Finally draw the page + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/server_analysis.php b/plugins/tidypics/pages/server_analysis.php new file mode 100644 index 0000000000000000000000000000000000000000..ccffc16329656782f268d4f62b598237d60431c9 --- /dev/null +++ b/plugins/tidypics/pages/server_analysis.php @@ -0,0 +1,138 @@ +<?php + +/******************************************************************** + * + * Tidypics System Analysis Script + * + * Helps admins configure their server + * + ********************************************************************/ + + include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + + global $CONFIG; + + admin_gatekeeper(); + + set_context('admin'); + + $title = 'TidyPics Server Analysis'; + + + function tp_readable_size($bytes) + { + if (strpos($bytes, 'M')) + return $bytes . 'B'; + + $size = $bytes / 1024; + if ($size < 1024) { + $size = number_format($size, 2); + $size .= ' KB'; + } else { + $size = $size / 1024; + if($size < 1024) { + $size = number_format($size, 2); + $size .= ' MB'; + } else { + $size = $size / 1024; + $size = number_format($size, 2); + $size .= ' GB'; + } + } + return $size; + } + + $disablefunc = explode(',', ini_get('disable_functions')); + $exec_avail = "Disabled"; + if (is_callable('exec') && !in_array('exec',$disablefunc)) + $exec_avail = "Enabled"; + + ob_start(); + + echo elgg_view_title($title); +?> +<div class="contentWrapper"> + <table width="100%"> + <tr> + <td>PHP version</td> + <td><?php echo phpversion(); ?></td> + <td></td> + </tr> + <tr> + <td>GD</td> + <td><?php echo (extension_loaded('gd')) ? 'Enabled' : 'Disabled'; ?></td> + <td>Elgg requires the GD extension to be loaded</td> + </tr> + <tr> + <td>IMagick PHP extension</td> + <td><?php echo (extension_loaded('imagick')) ? 'Enabled' : 'Disabled'; ?></td> + <td></td> + </tr> + <tr> + <td>exec()</td> + <td><?php echo $exec_avail; ?></td> + <td>Required for ImageMagick command line</td> + </tr> + <tr> + <td>Memory Available to PHP</td> + <td><?php echo tp_readable_size(ini_get('memory_limit')); ?></td> + <td>Change memory_limit to increase</td> + </tr> + <tr> + <td>Memory Used to Load This Page</td> + <td><?php if (function_exists('memory_get_peak_usage')) echo tp_readable_size(memory_get_peak_usage()); ?></td> + <td>This is approximately the minimum per page</td> + </tr> + <tr> + <td>Max File Upload Size</td> + <td><?php echo tp_readable_size(ini_get('upload_max_filesize')); ?></td> + <td>Max size of an uploaded image</td> + </tr> + <tr> + <td>Max Post Size</td> + <td><?php echo tp_readable_size(ini_get('post_max_size')); ?></td> + <td>Max post size = sum of images + html form</td> + </tr> + <tr> + <td>Max Input Time</td> + <td><?php echo ini_get('max_input_time'); ?> s</td> + <td>Time script waits for upload to finish</td> + </tr> + <tr> + <td>Max Execution Time</td> + <td><?php echo ini_get('max_execution_time'); ?> s</td> + <td>Max time a script will run</td> + </tr> + <tr> + <td>GD imagejpeg</td> + <td><?php echo (is_callable('imagejpeg')) ? 'Enabled' : 'Disabled'; ?></td> + <td></td> + </tr> + <tr> + <td>GD imagepng</td> + <td><?php echo (is_callable('imagepng')) ? 'Enabled' : 'Disabled'; ?></td> + <td></td> + </tr> + <tr> + <td>GD imagegif</td> + <td><?php echo (is_callable('imagegif')) ? 'Enabled' : 'Disabled'; ?></td> + <td></td> + </tr> + <tr> + <td>EXIF</td> + <td><?php echo (is_callable('exif_read_data')) ? 'Enabled' : 'Disabled'; ?></td> + <td></td> + </tr> + </table> + <div style="margin-top:20px;"> + <a href="<?php echo $CONFIG->url . "mod/tidypics/docs/configure_server.txt"; ?>">Server configuration doc</a> + </div> +</div> +<?php + + $content = ob_get_clean(); + + $body = elgg_view_layout('two_column_left_sidebar', '', $content); + + echo page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/tagged.php b/plugins/tidypics/pages/tagged.php new file mode 100644 index 0000000000000000000000000000000000000000..b5a87980998ab34a4ce5c4606fb5e2ef0ba65535 --- /dev/null +++ b/plugins/tidypics/pages/tagged.php @@ -0,0 +1,50 @@ +<?php + /** + * Tidypics Tagged Listing + * + * List all photos tagged with a user + */ + + include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + + + // Get user guid + $guid = get_input('guid'); + + $user = get_entity($guid); + + if ($user) + $title = sprintf(elgg_echo('tidypics:usertag'), $user->name); + else + $title = "User does not exist"; + + + + // create main column + $body = elgg_view_title($title); + + set_context('search'); + set_input('search_viewtype', 'gallery'); // need to force gallery view + $body .= list_entities_from_relationship('phototag', $guid, false, 'object', 'image', 0, 10, false); + + // Set up submenus + if (isloggedin()) { + add_submenu_item( elgg_echo("album:yours"), + $CONFIG->wwwroot . "pg/photos/owned/" . $_SESSION['user']->username, + 'tidypics-b' ); + } + add_submenu_item( elgg_echo('album:all'), + $CONFIG->wwwroot . "pg/photos/world/", + 'tidypics-z'); + add_submenu_item( elgg_echo('tidypics:mostrecent'), + $CONFIG->wwwroot . 'pg/photos/mostrecent', + 'tidypics-z'); + + + + $body = elgg_view_layout('two_column_left_sidebar','',$body); + + + page_draw($title,$body); + +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/thumbnail.php b/plugins/tidypics/pages/thumbnail.php new file mode 100644 index 0000000000000000000000000000000000000000..3aad5969d26b9881298d00db1e58b19d5a9bbc61 --- /dev/null +++ b/plugins/tidypics/pages/thumbnail.php @@ -0,0 +1,76 @@ +<?php + + /** + * Tidypics Thumbnail + * + */ + + // Get file GUID + $file_guid = (int) get_input('file_guid'); + + // Get file thumbnail size + $size = get_input('size'); + // only 3 possibilities + if ($size != 'small' && $size != 'thumb') { + $size = 'large'; + } + + $error_image = ''; + switch ($size) { + case 'thumb': + $error_image = "image_error_thumb.png"; + break; + case 'small': + $error_image = "image_error_small.png"; + break; + case 'large': + $error_image = "image_error_large.png"; + break; + } + + // Get file entity + $file = get_entity($file_guid); + if (!$file) + forward('mod/tidypics/graphics/' . $error_image); + + if ($file->getSubtype() != "image") + forward('mod/tidypics/graphics/' . $error_image); + + // Get filename + if ($size == "thumb") { + $thumbfile = $file->thumbnail; + } else if ($size == "small") { + $thumbfile = $file->smallthumb; + } else { + $thumbfile = $file->largethumb; + } + + if (!$thumbfile) + forward('mod/tidypics/graphics/' . $error_image); + + // create Elgg File object + $readfile = new ElggFile(); + $readfile->owner_guid = $file->owner_guid; + $readfile->setFilename($thumbfile); + $contents = $readfile->grabFile(); + + // send error image if file could not be read + if (!$contents) { + forward('mod/tidypics/graphics/' . $error_image); + } + + // expires every 14 days + $expires = 14 * 60*60*24; + + // overwrite header caused by php session code so images can be cached + $mime = $file->getMimeType(); + header("Content-Type: $mime"); + header("Content-Length: " . strlen($contents)); + header("Cache-Control: public", true); + header("Pragma: public", true); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expires) . ' GMT', true); + + // Return the thumbnail and exit + echo $contents; + exit; + \ No newline at end of file diff --git a/plugins/tidypics/pages/upload.php b/plugins/tidypics/pages/upload.php new file mode 100644 index 0000000000000000000000000000000000000000..84d23728755121456d77e03a79fcbb6b1a9ce97d --- /dev/null +++ b/plugins/tidypics/pages/upload.php @@ -0,0 +1,42 @@ +<?php + /** + * Tidypics Upload Images Page + * + */ + + include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + + // must be logged in to upload images + gatekeeper(); + + $album_guid = (int) get_input('container_guid'); + if (!$album_guid) + forward(); + + $album = get_entity($album_guid); + + //if album does not exist or user does not have access + if (!$album || !$album->canEdit()) { + // throw warning and forward to previous page + forward($_SERVER['HTTP_REFERER']); + } + + // set page owner based on container (user or group) + $container = $album->container_guid; + set_page_owner($container); + + $page_owner = page_owner_entity(); + if ($page_owner instanceof ElggGroup) { + add_submenu_item( sprintf(elgg_echo('album:group'),$page_owner->name), + $CONFIG->wwwroot . "pg/photos/owned/" . $page_owner->username); + } + + set_context('photos'); + $title = elgg_echo('album:addpix') . ': ' . $album->title; + $area2 .= elgg_view_title($title); + + $area2 .= elgg_view("tidypics/forms/upload", array('album' => $album_guid ) ); + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/viewalbum.php b/plugins/tidypics/pages/viewalbum.php new file mode 100644 index 0000000000000000000000000000000000000000..050b124cb54270f0ea8f014f0e8accccec5244aa --- /dev/null +++ b/plugins/tidypics/pages/viewalbum.php @@ -0,0 +1,68 @@ +<?php + + /** + * Tidypics Album View Page + * + * This displays a listing of all the photos that belong to an album + */ + + include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + + // if this page belongs to a closed group, prevent anyone outside group from seeing + if (is_callable('group_gatekeeper')) group_gatekeeper(); + + // get the album entity + $album_guid = (int) get_input('guid'); + $album = get_entity($album_guid); + + // panic if we can't get it + if (!$album) forward(); + + // container should always be set, but just in case + if ($album->container_guid) + set_page_owner($album->container_guid); + else + set_page_owner($album->owner_guid); + + $owner = page_owner_entity(); + + // setup group menu + if ($owner instanceof ElggGroup) { + add_submenu_item( sprintf(elgg_echo('album:group'),$owner->name), + $CONFIG->wwwroot . "pg/photos/owned/" . $owner->username); + } + + // allow other plugins to override the slideshow + $slideshow_link = trigger_plugin_hook('tp_slideshow', 'album', array('album' => $album), null); + if ($slideshow_link) { + add_submenu_item(elgg_echo('album:slideshow'), + $slideshow_link, + 'photos' ); + } + + if (can_write_to_container(0, $album->container_guid)) { + if ($owner instanceof ElggGroup) { + add_submenu_item( elgg_echo('album:create'), + $CONFIG->wwwroot . 'pg/photos/new/' . $owner->username, + 'photos'); + } + add_submenu_item( elgg_echo('album:addpix'), + $CONFIG->wwwroot . 'pg/photos/upload/' . $album_guid, + 'photos'); + add_submenu_item( elgg_echo('album:edit'), + $CONFIG->wwwroot . 'pg/photos/edit/' . $album_guid, + 'photos'); + $ts = time(); + $token = generate_action_token($ts); + add_submenu_item( elgg_echo('album:delete'), + $CONFIG->wwwroot . 'action/tidypics/delete?guid=' . $album_guid . '&__elgg_token=' . $token . '&__elgg_ts=' . $ts, + 'photos', + true); + } + + // create body + $area2 = elgg_view_entity($album, true); + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + + page_draw($album->title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/viewimage.php b/plugins/tidypics/pages/viewimage.php new file mode 100644 index 0000000000000000000000000000000000000000..025c1ad3ba40c2c7d29c8b922c3ed05cbc40eb84 --- /dev/null +++ b/plugins/tidypics/pages/viewimage.php @@ -0,0 +1,58 @@ +<?php + + /** + * Tidypics image view + * + * Display a view of a single image + */ + + // Load Elgg engine + include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + + // if this page belongs to a closed group, prevent anyone outside group from seeing + if (is_callable('group_gatekeeper')) group_gatekeeper(); + + // get the album entity + $photo_guid = (int) get_input('guid'); + $photo = get_entity($photo_guid); + + // panic if we can't get it + if (!$photo) forward(); + + // set page owner based on owner of photo album + set_page_owner($photo->owner_guid); + $album = get_entity($photo->container_guid); + if ($album) { + $owner_guid = $album->container_guid; + if ($owner_guid) + set_page_owner($owner_guid); + } + + + $page_owner = page_owner_entity(); + if ($page_owner instanceof ElggGroup) { + add_submenu_item( sprintf(elgg_echo('album:group'),$page_owner->name), + $CONFIG->wwwroot . "pg/photos/owned/" . $page_owner->username); + } + + if (can_write_to_container(0, $album->container_guid)) { + add_submenu_item( elgg_echo('image:edit'), + $CONFIG->wwwroot . 'pg/photos/edit/' . $photo_guid, + 'photos'); + $ts = time(); + $token = generate_action_token($ts); + add_submenu_item( elgg_echo('image:delete'), + $CONFIG->wwwroot . 'action/tidypics/delete?guid=' . $photo_guid . '&__elgg_token=' . $token . '&__elgg_ts=' . $ts, + 'photos', + true); + } + + + $title = $photo->title; + $area2 = elgg_view_title($title); + $area2 .= elgg_view_entity($photo, true); + + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/pages/world.php b/plugins/tidypics/pages/world.php new file mode 100644 index 0000000000000000000000000000000000000000..48a3345d4f2698e2481d25d7a92edca3b500375b --- /dev/null +++ b/plugins/tidypics/pages/world.php @@ -0,0 +1,29 @@ +<?php + /** + * Tidypics View All Albums on Site + * + */ + + include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/engine/start.php"; + + // set page owner to logged in user + if (isloggedin()) { + set_page_owner(get_loggedin_userid()); + } + + $num_albums = 16; + + $title = elgg_echo('album:all'); + $area2 = elgg_view_title($title); + + set_context('search'); + set_input('search_viewtype', 'gallery'); + $content .= tp_list_entities('object','album', 0, null, $num_albums, false); + set_context('photos'); + + $area2 = elgg_view('tidypics/content_wrapper', array('title' => $title, 'content' => $content,)); + + $body = elgg_view_layout('two_column_left_sidebar', '', $area2); + + page_draw($title, $body); +?> \ No newline at end of file diff --git a/plugins/tidypics/start.php b/plugins/tidypics/start.php new file mode 100644 index 0000000000000000000000000000000000000000..02f0c6414443f3a13f19c402ccc036e69e670ba8 --- /dev/null +++ b/plugins/tidypics/start.php @@ -0,0 +1,445 @@ +<?php + /** + * Elgg tidypics + * + */ + + // set some simple defines + define('TP_OLD_ALBUM', 0); + define('TP_NEW_ALBUM', 1); + + // include core libraries + include dirname(__FILE__) . "/lib/tidypics.php"; + include dirname(__FILE__) . "/lib/image.php"; + include dirname(__FILE__) . "/lib/album.php"; + + /** + * tidypics plugin initialisation functions. + */ + function tidypics_init() + { + global $CONFIG; + + // Set up menu for logged in users + if (isloggedin()) + { + add_menu(elgg_echo('photos'), $CONFIG->wwwroot . "pg/photos/owned/" . $_SESSION['user']->username); + } + + // Extend CSS + extend_view('css', 'tidypics/css'); + + // Extend hover-over and profile menu + extend_view('profile/menu/links','tidypics/hover_menu'); + + //group view ** psuedo widget view for group pages** + extend_view('groups/right_column','tidypics/groupprofile_albums'); + + // rss extensions + extend_view('extensions/xmlns', 'extensions/tidypics/xmlns'); + extend_view('extensions/channel', 'extensions/tidypics/channel'); + + // Register a page handler, so we can have nice URLs + register_page_handler('photos','tidypics_page_handler'); + + // Add a new tidypics widget + add_widget_type('album_view', elgg_echo("tidypics:widget:albums"), elgg_echo("tidypics:widget:album_descr"), 'profile'); + add_widget_type('latest_photos', elgg_echo("tidypics:widget:latest"), elgg_echo("tidypics:widget:latest_descr"), 'profile'); + + // Register a URL handler for files + register_entity_url_handler('tidypics_image_url', 'object', 'image'); + register_entity_url_handler('tidypics_album_url', 'object', 'album'); + + // add the class files for image and album + add_subtype("object", "image", "TidypicsImage"); + add_subtype("object", "album", "TidypicsAlbum"); + + // Register entity type + register_entity_type('object','image'); + register_entity_type('object','album'); + + if (function_exists('add_group_tool_option')) + add_group_tool_option('photos',elgg_echo('tidypics:enablephotos'),true); + + if (get_plugin_setting('grp_perm_override', 'tidypics') != "disabled") + register_plugin_hook('permissions_check', 'object', 'tidypics_permission_override'); + + // Register for notifications + if (is_callable('register_notification_object')) { + register_notification_object('object', 'album', elgg_echo('tidypics:newalbum')); + + register_plugin_hook('notify:entity:message', 'object', 'tidypics_notify_message'); + } + + // slideshow plugin hook + register_plugin_hook('tp_slideshow', 'album', 'tidypics_slideshow'); + } + + /** + * Sets up sidebar menus for tidypics. Triggered on pagesetup. + */ + function tidypics_submenus() { + + global $CONFIG; + + $page_owner = page_owner_entity(); + + if ($page_owner instanceof ElggGroup) { + if (get_context() == "groups") { + if ($page_owner->photos_enable != "no") { + add_submenu_item( sprintf(elgg_echo('album:group'),$page_owner->name), + $CONFIG->wwwroot . "pg/photos/owned/" . $page_owner->username); + } + } + } + // context is only set to photos on individual pages, not on group pages + else if (get_context() == "photos") { + + $view_count = get_plugin_setting('view_count', 'tidypics'); + + // owner gets "your albumn", "your friends albums", "your most recent", "your most viewed" + if (get_loggedin_userid() && get_loggedin_userid() == $page_owner->guid) { + + add_submenu_item( elgg_echo('album:create'), + $CONFIG->wwwroot . "pg/photos/new/{$page_owner->username}/", + 'tidypics-a' ); + + add_submenu_item( elgg_echo("album:yours"), + $CONFIG->wwwroot . "pg/photos/owned/{$page_owner->username}/", + 'tidypics-a' ); + + add_submenu_item( elgg_echo('album:yours:friends'), + $CONFIG->wwwroot . "pg/photos/friends/{$page_owner->username}/", + 'tidypics-a'); + + add_submenu_item( elgg_echo('tidypics:yourmostrecent'), + $CONFIG->wwwroot . "pg/photos/mostrecent/{$page_owner->username}/", + 'tidypics-a'); + + if ($view_count != 'disabled') { + add_submenu_item( elgg_echo('tidypics:yourmostviewed'), + $CONFIG->wwwroot . "pg/photos/mostviewed/{$page_owner->username}/", + 'tidypics-a'); + } + + } else if (isloggedin()) { + + $user = get_loggedin_user(); + + // logged in not owner gets "page owners albums", "page owner's friends albums", "page owner's most viewed", "page owner's most recent" + // and then "your albums", "your most recent", "your most viewed" + add_submenu_item( elgg_echo("album:yours"), + $CONFIG->wwwroot . "pg/photos/owned/{$user->username}/", + 'tidypics-b' ); + + add_submenu_item( elgg_echo('tidypics:yourmostrecent'), + $CONFIG->wwwroot . "pg/photos/mostrecent/{$user->username}/", + 'tidypics-b'); + + if ($view_count != 'disabled') { + add_submenu_item( elgg_echo('tidypics:yourmostviewed'), + $CONFIG->wwwroot . "pg/photos/mostviewed/{$user->username}/", + 'tidypics-b'); + } + + if ($page_owner->name) { // check to make sure the owner set their display name + add_submenu_item( sprintf(elgg_echo("album:user"), $page_owner->name), + $CONFIG->wwwroot . "pg/photos/owned/{$page_owner->username}/", + 'tidypics-a' ); + add_submenu_item( sprintf(elgg_echo('album:friends'),$page_owner->name), + $CONFIG->wwwroot . "pg/photos/friends/{$page_owner->username}/", + 'tidypics-a'); + + if ($view_count != 'disabled') { + add_submenu_item( sprintf(elgg_echo('tidypics:friendmostviewed'),$page_owner->name), + $CONFIG->wwwroot . "pg/photos/mostviewed/{$page_owner->username}/", + 'tidypics-a'); + } + + add_submenu_item( sprintf(elgg_echo('tidypics:friendmostrecent'),$page_owner->name), + $CONFIG->wwwroot . "pg/photos/mostrecent/{$page_owner->username}/", + 'tidypics-a'); + } + } else if ($page_owner->guid) { + // non logged in user gets "page owners albums", "page owner's friends albums" + add_submenu_item( sprintf(elgg_echo("album:user"), $page_owner->name), + $CONFIG->wwwroot . "pg/photos/owned/{$page_owner->username}/", + 'tidypics-a' ); + add_submenu_item( sprintf(elgg_echo('album:friends'),$page_owner->name), + $CONFIG->wwwroot . "pg/photos/friends/{$page_owner->username}/", + 'tidypics-a'); + } + + // everyone gets world albums, most recent, most viewed, most recently viewed, recently commented + add_submenu_item( elgg_echo('album:all'), + $CONFIG->wwwroot . "pg/photos/world/", + 'tidypics-z'); + add_submenu_item( elgg_echo('tidypics:mostrecent'), + $CONFIG->wwwroot . 'pg/photos/mostrecent/', + 'tidypics-z'); + + if ($view_count != 'disabled') { + add_submenu_item( elgg_echo('tidypics:mostviewed'), + $CONFIG->wwwroot . 'pg/photos/mostviewed/', + 'tidypics-z'); + add_submenu_item( elgg_echo('tidypics:recentlyviewed'), + $CONFIG->wwwroot . 'pg/photos/recentlyviewed/', + 'tidypics-z'); + } + add_submenu_item( elgg_echo('tidypics:recentlycommented'), + $CONFIG->wwwroot . 'pg/photos/recentlycommented/', + 'tidypics-z'); +/* + add_submenu_item( 'Flickr Integration', + $CONFIG->wwwroot . 'mod/tidypics/pages/flickr/setup.php', + 'tidypics-z'); +*/ + } + + } + + /** + * Sets up tidypics admin menu. Triggered on pagesetup. + */ + function tidypics_adminmenu() + { + global $CONFIG; + if (get_context() == 'admin' && isadminloggedin()) { + add_submenu_item(elgg_echo('tidypics:administration'), $CONFIG->url . "mod/tidypics/pages/admin.php"); + } + } + + /** + * Sets up submenus for tidypics most viewed pages + */ + function tidypics_mostviewed_submenus() { + + global $CONFIG; + + add_submenu_item(elgg_echo('tidypics:mostvieweddashboard'), $CONFIG->url . "mod/tidypics/mostvieweddashboard.php"); + add_submenu_item(elgg_echo('tidypics:mostviewedthisyear'), $CONFIG->url . "mod/tidypics/pages/lists/mostviewedimagesthisyear.php"); + add_submenu_item(elgg_echo('tidypics:mostviewedthismonth'), $CONFIG->url . "mod/tidypics/pages/lists/mostviewedimagesthismonth.php"); + add_submenu_item(elgg_echo('tidypics:mostviewedlastmonth'), $CONFIG->url . "mod/tidypics/pages/lists/mostviewedimageslastmonth.php"); + add_submenu_item(elgg_echo('tidypics:mostviewedtoday'), $CONFIG->url . "mod/tidypics/pages/lists/mostviewedimagestoday.php"); + add_submenu_item(elgg_echo('tidypics:mostcommented'), $CONFIG->url . "mod/tidypics/pages/lists/mostcommentedimages.php"); + add_submenu_item(elgg_echo('tidypics:mostcommentedthismonth'), $CONFIG->url . "mod/tidypics/pages/lists/mostcommentedimagesthismonth.php"); + add_submenu_item(elgg_echo('tidypics:mostcommentedtoday'), $CONFIG->url . "mod/tidypics/pages/lists/mostcommentedimagestoday.php"); + add_submenu_item(elgg_echo('tidypics:recentlycommented'), $CONFIG->wwwroot . 'pg/photos/recentlycommented/'); + } + + /** + * tidypics page handler + * + * @param array $page Array of page elements, forwarded by the page handling mechanism + */ + function tidypics_page_handler($page) { + + global $CONFIG; + + if (isset($page[0])) + { + switch($page[0]) + { + case "owned": //view list of albums owned by container + if (isset($page[1])) set_input('username',$page[1]); + include($CONFIG->pluginspath . "tidypics/pages/ownedalbums.php"); + break; + + case "view": //view an image individually + if (isset($page[1])) set_input('guid',$page[1]); + include($CONFIG->pluginspath . "tidypics/pages/viewimage.php"); + break; + + case "album": //view an album individually + if (isset($page[1])) set_input('guid',$page[1]); + include($CONFIG->pluginspath . "tidypics/pages/viewalbum.php"); + break; + + case "new": //create new album + if (isset($page[1])) set_input('username',$page[1]); + include($CONFIG->pluginspath . "tidypics/pages/newalbum.php"); + break; + + case "upload": //upload images to album + if (isset($page[1])) set_input('container_guid',$page[1]); + include($CONFIG->pluginspath . "tidypics/pages/upload.php"); + break; + + case "edit": //edit image or album + if (isset($page[1])) set_input('guid',$page[1]); + include($CONFIG->pluginspath . "tidypics/pages/edit.php"); + break; + + case "friends": // albums of friends + if (isset($page[1])) set_input('username',$page[1]); + include($CONFIG->pluginspath . "tidypics/pages/friends.php"); + break; + + case "world": // all site albums + include($CONFIG->pluginspath . "tidypics/pages/world.php"); + break; + + case "download": // download an image + if (isset($page[1])) set_input('file_guid', $page[1]); + if (isset($page[2])) set_input('type', $page[2]); + include($CONFIG->pluginspath . "tidypics/pages/download.php"); + break; + + case "thumbnail": // tidypics thumbnail + if (isset($page[1])) set_input('file_guid', $page[1]); + if (isset($page[2])) set_input('size', $page[2]); + include($CONFIG->pluginspath . "tidypics/pages/thumbnail.php"); + break; + + case "tagged": // all photos tagged with user + if (isset($page[1])) set_input('guid',$page[1]); + include($CONFIG->pluginspath . "tidypics/pages/tagged.php"); + break; + + case "mostviewed": // images with the most views + if (isset($page[1])) set_input('username',$page[1]); + include($CONFIG->pluginspath . "tidypics/pages/lists/mostviewedimages.php"); + break; + + case "mostrecent": // images uploaded most recently + if (isset($page[1])) set_input('username',$page[1]); + include($CONFIG->pluginspath . "tidypics/pages/lists/mostrecentimages.php"); + break; + + case "recentlyviewed": // images most recently viewed + include($CONFIG->pluginspath . "tidypics/pages/lists/recentlyviewed.php"); + break; + + case "recentlycommented": // images with the most recent comments + include($CONFIG->pluginspath . "tidypics/pages/lists/recentlycommented.php"); + break; + + case "highestrated": // images with the highest average rating + include($CONFIG->pluginspath . "tidypics/pages/lists/highestrated.php"); + break; + + case "flickr": + if (isset($page[1])) set_input('username',$page[1]); + include($CONFIG->pluginspath . "tidypics/pages/flickr/setup.php"); + break; + } + } + else + { + // going to all site albums if something goes wrong with the page handler + include($CONFIG->pluginspath . "tidypics/pages/world.php"); + } + + } + + /** + * Override permissions for group albums and images + * + */ + function tidypics_permission_override($hook, $entity_type, $returnvalue, $params) + { + $entity = $params['entity']; + $user = $params['user']; + + if ($entity->subtype == get_subtype_id('object', 'album')) { + // test that the user can edit the container + return can_write_to_container(0, $entity->container_guid); + } + + if ($entity->subtype == get_subtype_id('object', 'image')) { + // test that the user can edit the container + return can_write_to_container(0, $entity->container_guid); + } + } + + + /** + * Notification message handler + */ + function tidypics_notify_message($hook, $entity_type, $returnvalue, $params) + { + $entity = $params['entity']; + $to_entity = $params['to_entity']; + $method = $params['method']; + if (($entity instanceof ElggEntity) && ($entity->getSubtype() == 'album')) + { + // block notification message when the album doesn't have any photos + if ($entity->new_album == TP_NEW_ALBUM) + return false; + + $descr = $entity->description; + $title = $entity->title; + $owner = $entity->getOwnerEntity(); + return sprintf(elgg_echo('album:river:created'), $owner->name) . ': ' . $title . "\n\n" . $descr . "\n\n" . $entity->getURL(); + } + return null; + } + + /** + * Populates the ->getUrl() method for file objects + * Registered in the init function + * + * @param ElggEntity $entity album/image entity + * @return string File URL + */ + function tidypics_image_url($entity) { + global $CONFIG; + $title = $entity->title; + $title = friendly_title($title); + return $CONFIG->url . "pg/photos/view/" . $entity->getGUID() . "/" . $title; + } + + function tidypics_album_url($entity) { + global $CONFIG; + $title = $entity->title; + $title = friendly_title($title); + return $CONFIG->url . "pg/photos/album/" . $entity->getGUID() . "/" . $title; + } + + + /** + * Catch the plugin hook and add the default album slideshow + * + * @param $hook - 'tidypics:slideshow' + * @param $entity_type - 'album' + * @param $returnvalue - if set, return because another plugin has used the hook + * @param $params - arry containing album entity + * @return unknown_type + */ + function tidypics_slideshow($hook, $entity_type, $returnvalue, $params) { + + if ($returnvalue !== null) { + // someone has already added a slideshow or requested that the slideshow is not used + return $returnvalue; + } + + $slideshow_link = "javascript:PicLensLite.start({maxScale:0,feedUrl:location.href+'?view=rss'})"; + + // add the slideshow javascript to the header + extend_view('metatags', 'tidypics/js/slideshow'); + + return $slideshow_link; + } + + function tp_mostrecentimages($max = 8, $pagination = true) { + return list_entities("object", "image", 0, $max, false, false, $pagination); + } + + + // Make sure tidypics_init is called on initialisation + register_elgg_event_handler('init','system','tidypics_init'); + register_elgg_event_handler('pagesetup','system','tidypics_submenus'); + register_elgg_event_handler('pagesetup','system','tidypics_adminmenu'); + + // Register actions + register_action("tidypics/settings", false, $CONFIG->pluginspath . "tidypics/actions/settings.php"); + register_action("tidypics/upload", false, $CONFIG->pluginspath . "tidypics/actions/upload.php"); + register_action("tidypics/addalbum", false, $CONFIG->pluginspath. "tidypics/actions/addalbum.php"); + register_action("tidypics/edit", false, $CONFIG->pluginspath. "tidypics/actions/edit.php"); + register_action("tidypics/delete", false, $CONFIG->pluginspath. "tidypics/actions/delete.php"); + register_action("tidypics/edit_multi", false, $CONFIG->pluginspath. "tidypics/actions/edit_multi.php"); + register_action("tidypics/addtag", true, $CONFIG->pluginspath . "tidypics/actions/addtag.php"); + register_action("tidypics/deletetag", true, $CONFIG->pluginspath . "tidypics/actions/deletetag.php"); + register_action("tidypics/flickrSetup", true, $CONFIG->pluginspath . "tidypics/actions/flickrSetup.php"); + +?> \ No newline at end of file diff --git a/plugins/tidypics/thumbnail.php b/plugins/tidypics/thumbnail.php new file mode 100644 index 0000000000000000000000000000000000000000..79d4872107c0332d5e82ead4ef22d73797dbda83 --- /dev/null +++ b/plugins/tidypics/thumbnail.php @@ -0,0 +1,78 @@ +<?php + + /** + * Tidypics Thumbnail + * + */ + + include_once(dirname(dirname(dirname(__FILE__))) . "/engine/start.php"); + + // Get file GUID + $file_guid = (int) get_input('file_guid'); + + // Get file thumbnail size + $size = get_input('size'); + // only 3 possibilities + if ($size != 'small' && $size != 'thumb') { + $size = 'large'; + } + + $error_image = ''; + switch ($size) { + case 'thumb': + $error_image = "image_error_thumb.png"; + break; + case 'small': + $error_image = "image_error_small.png"; + break; + case 'large': + $error_image = "image_error_large.png"; + break; + } + + // Get file entity + $file = get_entity($file_guid); + if (!$file) + forward('mod/tidypics/graphics/' . $error_image); + + if ($file->getSubtype() != "image") + forward('mod/tidypics/graphics/' . $error_image); + + // Get filename + if ($size == "thumb") { + $thumbfile = $file->thumbnail; + } else if ($size == "small") { + $thumbfile = $file->smallthumb; + } else { + $thumbfile = $file->largethumb; + } + + if (!$thumbfile) + forward('mod/tidypics/graphics/' . $error_image); + + // create Elgg File object + $readfile = new ElggFile(); + $readfile->owner_guid = $file->owner_guid; + $readfile->setFilename($thumbfile); + $contents = $readfile->grabFile(); + + // send error image if file could not be read + if (!$contents) { + forward('mod/tidypics/graphics/' . $error_image); + } + + // expires every 14 days + $expires = 14 * 60*60*24; + + // overwrite header caused by php session code so images can be cached + $mime = $file->getMimeType(); + header("Content-Type: $mime"); + header("Content-Length: " . strlen($contents)); + header("Cache-Control: public", true); + header("Pragma: public", true); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expires) . ' GMT', true); + + // Return the thumbnail and exit + echo $contents; + exit; +?> diff --git a/plugins/tidypics/vendors/PicLensLite/NoFlash.jpg b/plugins/tidypics/vendors/PicLensLite/NoFlash.jpg new file mode 100644 index 0000000000000000000000000000000000000000..94f643dc7824f1179fec635c245d852f8cfbcb03 Binary files /dev/null and b/plugins/tidypics/vendors/PicLensLite/NoFlash.jpg differ diff --git a/plugins/tidypics/vendors/PicLensLite/PicLensLite.swf b/plugins/tidypics/vendors/PicLensLite/PicLensLite.swf new file mode 100644 index 0000000000000000000000000000000000000000..3bfd4ea495027027b457595699afe0a23fbe5949 Binary files /dev/null and b/plugins/tidypics/vendors/PicLensLite/PicLensLite.swf differ diff --git a/plugins/tidypics/vendors/PicLensLite/piclens_optimized.js b/plugins/tidypics/vendors/PicLensLite/piclens_optimized.js new file mode 100644 index 0000000000000000000000000000000000000000..48cea086b4ea7903b1d7eb9de5a68a1270409e72 --- /dev/null +++ b/plugins/tidypics/vendors/PicLensLite/piclens_optimized.js @@ -0,0 +1,20 @@ +/* PicLens Lite: version 1.3.1 (14221) + * Copyright (c) 2008 Cooliris, Inc. All Rights Reserved. + * + * The JavaScript part of PicLens Lite (i.e., this file) is BSD licensed (see: http://lite.piclens.com/bsdlicense) + * This launcher includes and interacts with SWFObject (MIT), BrowserDetect (BSD Compatible), and Lytebox (CC Attribution 3.0). + * + * There are two versions of this JS: + * http://lite.piclens.com/current/piclens.js full commented file (~39KB) + * http://lite.piclens.com/current/piclens_optimized.js lighter deployment file (~21KB) + */ +var PicLensLite={start:function(B){this.determineBrowserParams();clearTimeout(this.REMOVE_TIMER_ID);clearTimeout(this.AUTO_CLOSE_TIMER_ID);this.ARGS={};if(typeof B!=="undefined"&&B!==null){this.ARGS=B;if(B.feedUrl){this.THE_FEED_URL=B.feedUrl;if(this.checkForPluginAndLaunchIfPossible(B.feedUrl,B.guid)){return }if(B.loadFeedInFlash){this.showFlashUI("")}else{this.loadViaXHR(B.feedUrl)}}if(typeof B.feedData!=="undefined"){this.showFlashUI(B.feedData)}}else{var A=this.indexFeeds();if(A.length!==0){var C=A[0];this.THE_FEED_URL=C.url;if(this.checkForPluginAndLaunchIfPossible(C.url)){return }this.loadViaXHR(C.url)}}},isRunning:function(){return this.LITE_IS_RUNNING},hasClient:function(){return this.hasCooliris()},addCustomButton:function(C,B,A){this.CUSTOM_BUTTON={targetURL:C,labelText:B,iconImage:A}},setCallbacks:function(A){if(A.onNoPlugins){this.ON_NO_PLUGINS=A.onNoPlugins}if(A.onExit){this.ON_EXIT=A.onExit}},setLiteURLs:function(A){if(!this.LITE_URL){if(A.swf){this.LITE_URL=A.swf}else{if(A.lite){this.LITE_URL=A.lite+"PicLensLite.swf"}}}if(!this.BUTTON_URL){if(A.button){this.BUTTON_URL=A.button}else{if(A.lite){this.BUTTON_URL=A.lite+"NoFlash.jpg"}}}var B="";if(A.lbox){B=A.lbox}else{if(A.lite){B=A.lite+"../lytebox/"}}if(!this.LBOX_CSS_URL){if(A.lboxcss){this.LBOX_CSS_URL=A.lboxcss}else{if(B!=""){this.LBOX_CSS_URL=B+"lytebox.css"}}}if(!this.LBOX_JS_URL){if(A.lboxjs){this.LBOX_JS_URL=A.lboxjs}else{if(B!=""){this.LBOX_JS_URL=B+"lytebox.js"}}}},ARGS:{},DEBUG_NOCLIENT:false,DEBUG_NOFLASH:false,HPAD:60,VPAD:20,LITE_BG_DIV:null,LITE_FG_DIV:null,LITE_URL:null,BUTTON_URL:null,LBOX_CSS_URL:null,LBOX_JS_URL:null,LBOX_COUNT:0,SHOW_LBOX:false,OS_WIN:false,OS_MAC:false,BROWSER_FFX:false,BROWSER_SAF:false,BROWSER_IE:false,BROWSER_IE6:false,OLD_B_MARGIN:null,OLD_B_OVERFLOW:null,OLD_B_HEIGHT:null,OLD_H_OVERFLOW:null,OLD_H_HEIGHT:null,THE_FEED:"",THE_FEED_URL:"",LITE_IS_RUNNING:false,piclensIsRunning_:false,FLASH_ID_1:"pllflash1",FLASH_ID_2:"pllflash2",FLASH_VER:null,FLASH_URL:"http://www.adobe.com/go/getflashplayer",PL_URL:"http://download.piclens.com/partner/",PLC:null,LEARN_PL_URL:"http://affiliate.piclens.com/partner/",FONT:"font-family: Lucida Grande, Myriad Pro, Verdana, Helvetica, Arial, sans-serif;",KEY_HANDLERS:"",ON_NO_PLUGINS:null,ON_EXIT:null,AUTO_CLOSE_TIMER_ID:0,REMOVE_TIMER_ID:0,RESIZE_TIMER_IE6:null,RESIZE_HANDLER_EXISTS:false,CUSTOM_BUTTON:null,addKeyHandlers:function(){var A=this;if(typeof document.onkeydown!=="undefined"){this.KEY_HANDLERS=document.onkeydown}document.onkeydown=function(C){var B;if(typeof C==="undefined"||C===null){B=window.event.keyCode}else{B=C.which}var D=A.handleKeyPress(B);if(typeof C!="undefined"&&C!=null){C.returnValue=D}return D}},addMouseHandlers:function(){if(window.addEventListener){window.addEventListener("DOMMouseScroll",this.handleMouseWheel,false)}else{if(document.attachEvent){document.attachEvent("onmousewheel",this.handleMouseWheel)}}window.onmousewheel=document.onmousewheel=this.handleMouseWheel},appendElementsToDocument:function(){if(this.BROWSER_FFX&&this.OS_MAC){this.LITE_BG_DIV.style.display="none"}document.body.appendChild(this.LITE_BG_DIV);document.body.appendChild(this.LITE_FG_DIV)},autoResize:function(){if(!this.isRunning()){clearInterval(this.RESIZE_TIMER_IE6);return }var C=this.getPageSize();var B=this.LITE_BG_DIV;if(B){B.style.height=C.h+"px";B.style.width=C.w+"px"}if(this.LITE_FG_DIV){var A=this.LITE_FG_DIV.style;this.resizeToPaddedBox(A);this.resizeToFitPaddedBox(A,C);this.resizeFlashToFitPaddedBox()}},checkForPluginAndLaunchIfPossible:function(B,A){if(this.hasCooliris()){if(typeof (A)!="undefined"){this.PLC.launch(B,"uid",A)}else{this.PLC.launch(B,"","")}return true}return false},createBackgroundOverlay:function(){var D=document.createElement("div");this.LITE_BG_DIV=D;D.id="lite_bg_div";var E=D.style;E.position="fixed";E.width=E.height="100%";if(this.BROWSER_IE6){var A=document.body;var C=A.currentStyle;var H=document.documentElement;var G=H.currentStyle;this.OLD_B_MARGIN=C.margin;this.OLD_B_OVERFLOW=C.overflow;this.OLD_B_HEIGHT=C.height;this.OLD_H_OVERFLOW=G.overflow;this.OLD_H_HEIGHT=G.height;this.OLD_SCROLL_Y=H.scrollTop;A.style.margin="0";A.style.overflow="auto";A.style.height="100%";H.style.overflow="auto";H.style.height="100%";E.position="absolute";var F=this.getPageSize();E.height=F.h+"px";E.width=F.w+"px"}E.left=E.right=E.top=E.bottom="0";E.backgroundColor="#000";E.zIndex=1000;E.opacity="0.5";E.filter="alpha(opacity=50)";var B=this;D.onclick=function(){B.exitPicLensLite()}},createForegroundFlashComponent:function(){var B=document.createElement("div");this.LITE_FG_DIV=B;B.id="lite_fg_div";var A=B.style;A.backgroundColor="#000";A.position="fixed";A.border="2px solid #555";A.zIndex=1001;this.resizeToPaddedBox(A);if(this.BROWSER_IE6){A.position="absolute";this.resizeToFitPaddedBox(A)}},closeFlashUI:function(C){var B=document;B.onkeydown=this.KEY_HANDLERS;window.onmousewheel=B.onmousewheel="";if(window.removeEventListener){window.removeEventListener("DOMMouseScroll",this.handleMouseWheel,false)}if(B.detachEvent){B.detachEvent("onmousewheel",this.handleMouseWheel)}this.LITE_BG_DIV.style.display=this.LITE_FG_DIV.style.display="none";this.REMOVE_TIMER_ID=setTimeout(function(){PicLensLite.removeChildren()},150);if(this.BROWSER_IE6){var A=document.body;var D=document.documentElement;A.style.margin=this.OLD_B_MARGIN;A.style.overflow=this.OLD_B_OVERFLOW;A.style.height=this.OLD_B_HEIGHT;D.style.overflow=this.OLD_H_OVERFLOW;D.style.height=this.OLD_H_HEIGHT;window.scrollTo(0,this.OLD_SCROLL_Y)}if(this.ON_EXIT!==null){this.ON_EXIT(C)}this.setRunningFlag(false)},determineBrowserParams:function(){var B=BrowserDetect.OS;var A=BrowserDetect.browser;this.OS_MAC=(B=="Mac");this.OS_WIN=(B=="Windows");this.BROWSER_FFX=(A=="Firefox");this.BROWSER_SAF=(A=="Safari");this.BROWSER_IE=(A=="Explorer");this.BROWSER_IE6=(this.BROWSER_IE&&BrowserDetect.version=="6");this.FLASH_VER=swfobjlite.getFlashPlayerVersion()},exitPicLensLite:function(){var A=this.getFlash();if(A!==null&&A.fl_exitPicLensLite){A.fl_exitPicLensLite();this.AUTO_CLOSE_TIMER_ID=setTimeout(function(){if(PicLensLite.isRunning()){PicLensLite.closeFlashUI()}},500)}else{this.closeFlashUI()}},findScriptLocation:function(){var E=document.getElementsByTagName("script");for(var C=0;C!=E.length;++C){var A=E[C];var D=A.getAttribute("type");if(D=="text/javascript"){var F=A.getAttribute("src");if(F===null){continue}var B=F.indexOf("piclens.js");if(B!=-1){this.setLiteURLs({lite:F.substring(0,B)});return }else{B=F.indexOf("piclens_optimized.js");if(B!=-1){this.setLiteURLs({lite:F.substring(0,B)});return }}}}},getPageSize:function(){var J,F,G,C;var I=document;var E=I.body;var D;if(window.innerHeight&&window.scrollMaxY){J=I.scrollWidth;F=(this.isFrame?parent.innerHeight:self.innerHeight)+(this.isFrame?parent.scrollMaxY:self.scrollMaxY)}else{if(E.scrollHeight>E.offsetHeight){J=E.scrollWidth;F=E.scrollHeight}else{D=I.getElementsByTagName("html").item(0);J=D.offsetWidth;F=D.offsetHeight;J=(J<E.offsetWidth)?E.offsetWidth:J;F=(F<E.offsetHeight)?E.offsetHeight:F}}var A=I.documentElement;if(self.innerHeight){G=(this.isFrame)?parent.innerWidth:self.innerWidth;C=(this.isFrame)?parent.innerHeight:self.innerHeight}else{if(A&&A.clientHeight){G=A.clientWidth;C=A.clientHeight}else{if(E){D=I.getElementsByTagName("html").item(0);G=D.clientWidth;C=D.clientHeight;G=(G==0)?E.clientWidth:G;C=(C==0)?E.clientHeight:C}}}var B=(F<C)?C:F;var H=(J<G)?G:J;return{pw:H,ph:B,w:G,h:C}},getElementsFromXMLFeed:function(){var B;if(window.ActiveXObject){B=new ActiveXObject("Microsoft.XMLDOM");B.async=false;B.loadXML(PicLensLite.THE_FEED)}else{var C=new DOMParser();B=C.parseFromString(PicLensLite.THE_FEED,"text/xml")}var A=B.getElementsByTagName("*");return A},getBasicSlideShowHTML:function(){if(!this.LBOX_JS_URL||!this.LBOX_CSS_URL){return""}var D=document.getElementsByTagName("head").item(0);var A=document.createElement("script");A.src=this.LBOX_JS_URL;A.type="text/javascript";D.appendChild(A);var G=document.createElement("link");G.rel="stylesheet";G.href=this.LBOX_CSS_URL;G.type="text/css";G.media="screen";D.appendChild(G);var F=this.getElementsFromXMLFeed();var C;var H="";for(C=0;C<F.length;C++){if(F[C].nodeName=="media:content"){var B=F[C].getAttribute("url");if(B.indexOf(".flv")==-1){H+='<a id="lboxImage" href="'+B+'" rel="lytebox[lite]"></a> '}}}var E="<div id='lightbox_images' align='center' style='display: none; padding-top:10px; color:#FFFFFF; font-size:.8em; "+this.FONT+" color:#999999;'>";E+='( Alternatively, <a onclick="javascript:PicLensLite.invokeLytebox();return false;" href="#" style="color:#656588">click here for a basic slideshow</a>. )';E+=H;E+="</div><br/>";return E},generateAlternativeContent:function(){var J='<div id="altContent" style="text-align:center; margin: 0 0 0 0; padding: 0 0 0 0; background-color: #000; min-width:860px;">';J+='<div align="center" style="width: 100%; padding-top:60px; '+this.FONT+'">';var I=this.FLASH_VER;var G;if(I.major>0){G="update your Flash Player from version "+I.major+"."+I.minor+"."+I.release+" to version 9.0.28 or newer"}else{G="install the most recent Flash Player"}var D="";if(this.THE_FEED!==""){D=this.getBasicSlideShowHTML()}var A=this.PL_URL;var E=this.LEARN_PL_URL;var F=this.ARGS.pid;if(F){A+=F+"/";E+=F+"/"}else{var H="000000000001/";A+=H;E+=H}if(this.SHOW_LBOX){}else{var C="<span style='padding-left:25px; color:#C6C6C6; font-size:";J+="<div style='padding:10px;'>"+C+"1.5em; font-weight: bold; "+this.FONT+"'>You're clicks away from going full screen!</span><br/>"+C+".9em; padding-bottom: 15px; "+this.FONT+"'>You must get the <a href='"+A+"' style='color:#656588'>Cooliris</a> browser plugin, or "+G+".</span></div>";if(!this.BUTTON_URL){J+='<a href="'+A+'" style="color:#ACD">Get Cooliris Now!</a>'}else{var B='<area shape="rect" coords=';J+='<img src="'+this.BUTTON_URL+'" alt="" border="0" usemap="#Map"><map name="Map" id="Map">'+B+'"0,0,33,33" href="#" onclick="javascript:PicLensLite.closeFlashUI();" />'+B+'"35,35,325,325" href="'+A+'" />'+B+'"593,209,825,301" href="'+this.FLASH_URL+'" />'+B+'"327,148,448,178" href="'+E+'" /></map>'}}J+="</div>";J+=D;J+='<div align="center" style="color:#666666; font-size:11px; '+this.FONT+'">© 2008 Cooliris, Inc. All trademarks are property of their respective holders.<br/><br/><br/></div>';J+="</div>";return J},generateFlashVars:function(){var C="";var B=this.ARGS;if(typeof B.guid!=="undefined"){C+="&startItemGUID="+B.guid}if(B.loadFeedInFlash){C+="&feedURL="+encodeURIComponent(this.THE_FEED_URL)}if(B.paused){C+="&paused="+B.paused}if(B.loop){C+="&loop="+B.loop}if(B.delay){C+="&delay="+B.delay}if(B.pid){C+="&pid="+B.pid}if(typeof B.maxScale!="undefined"){C+="&maxScale="+B.maxScale}if(typeof B.overlayToolbars!="undefined"){C+="&overlayToolbars="+B.overlayToolbars}var A=this.CUSTOM_BUTTON;if(A!=null){C+="&cButtonURL="+encodeURIComponent(A.targetURL);if(A.labelText!=null){C+="&cButtonLabel="+encodeURIComponent(A.labelText)}if(A.iconImage!=null){C+="&cButtonIcon="+encodeURIComponent(A.iconImage)}}C+="&swfURL="+encodeURIComponent(this.LITE_URL);C=C.substring(1);return C},getFlash:function(){if(this.BROWSER_SAF||this.BROWSER_IE){return document.getElementById(this.FLASH_ID_1)}else{return document.getElementById(this.FLASH_ID_2)}},getWindowSize:function(){var B=document.documentElement;var D=document.body;var A=0,C=0;if(typeof (window.innerWidth)=="number"){A=window.innerWidth;C=window.innerHeight}else{if(B&&(B.clientWidth||B.clientHeight)){A=B.clientWidth;C=B.clientHeight}else{if(D&&(D.clientWidth||D.clientHeight)){A=D.clientWidth;C=D.clientHeight}}}return{w:A,h:C}},handleKeyPress:function(A){if(!this.isRunning()){return true}var B=this.getFlash();if(B!=null&&B.fl_keyPressed){B.fl_keyPressed(A)}else{if(A==27){this.closeFlashUI();return false}}if(A==9||A==13){return false}return true},handleMouseWheel:function(A){var C=0;if(!A){A=window.event}if(A.wheelDelta){C=A.wheelDelta/120;if(window.opera){C=-C}}else{if(A.detail){var B=A.detail;if(Math.abs(B)<3){C=-B}else{C=-B/3}}}if(C){PicLensLite.sendMouseScrollToFlash(C)}if(A.preventDefault){A.preventDefault()}A.returnValue=false;return false},hasPicLensClient:function(){return this.hasCooliris()},hasCooliris:function(){if(this.DEBUG_NOCLIENT){return false}var E=false;if(this.PLC){E=true}else{if(window.piclens&&window.piclens.launch){this.PLC=window.piclens;E=true}else{var B=null;if(typeof PicLensContext!="undefined"){B=new PicLensContext()}else{try{B=new ActiveXObject("PicLens.Context")}catch(D){if(navigator.mimeTypes["application/x-cooliris"]){B=document.createElement("object");B.style.height="0px";B.style.width="0px";B.type="application/x-cooliris";document.documentElement.appendChild(B)}else{B=null}}}this.PLC=B;if(this.PLC){E=true}}}if(E){if(this.BROWSER_SAF){return true}var A;try{A=this.PLC.version}catch(D){return false}var C=A.split(".");if(C[0]>1){return true}else{if(C[0]==1){if(C[1]>6){return true}else{if(C[1]==6){if(C[2]>0){return true}else{if(C[2]==0){if(C[3]>=824){return true}}}}}}}return false}else{return false}},invokeLytebox:function(){this.SHOW_LBOX=true;myLytebox.start(document.getElementById("lboxImage"),false,false);this.closeFlashUI()},showLyteboxLink:function(){myLytebox.updateLyteboxItems();myLytebox.doAnimations=false;var A=document.getElementById("lightbox_images");if(A!=null){A.style.display="block";if(this.SHOW_LBOX&&this.getFlash()==null){this.invokeLytebox()}}},startLytebox:function(){if(typeof myLytebox!="undefined"){this.showLyteboxLink()}else{if(typeof initLytebox!="undefined"){initLytebox();this.showLyteboxLink()}else{if(this.LBOX_COUNT>=4){return }setTimeout(function(){PicLensLite.startLytebox()},150);this.LBOX_COUNT++}}},injectFlashPlayer:function(){var A=this.LITE_FG_DIV;var D;var F;D=F="100%";if(this.BROWSER_IE6){D=F="0"}var E=this.generateFlashVars();var B=this.generateAlternativeContent();if(this.meetsReqs()){var C="<param name=";A.innerHTML='<object id="'+this.FLASH_ID_1+'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%">'+C+'"movie" value="'+this.LITE_URL+'" />'+C+'"quality" value="high"/> '+C+'"bgcolor" value="#000000"/> '+C+'"allowScriptAccess" value="always"/> '+C+'"FlashVars" value="'+E+'"/> '+C+'"allowFullScreen" value="true"/> '+C+'"wmode" value="window"/> '+C+'"scale" value="noscale"/> <object type="application/x-shockwave-flash" data="'+this.LITE_URL+'" width="'+D+'" height="'+F+'" quality="high" bgcolor="#000000" id="'+this.FLASH_ID_2+'" quality="high" FlashVars="'+E+'" allowFullScreen="true" scale="noscale" wmode="window" allowScriptAccess="always">'+B+"</object></object>"}else{if(this.ON_NO_PLUGINS){this.ON_NO_PLUGINS()}else{A.innerHTML=B;A.style.minWidth="860px";A.style.minHeight="550px"}}if(this.BROWSER_SAF){this.resizeUI()}},indexFeeds:function(){var E=document.getElementsByTagName("link");var A=[];for(var B=0;B!=E.length;++B){var D=E[B],C=D.getAttribute("type");if(C=="application/rss+xml"||C=="text/xml"){A.push({title:D.getAttribute("title"),url:D.getAttribute("href")})}}return A},loadViaXHR:function(B){var A=this;var D=window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject("MSXML2.XMLHTTP.3.0");try{D.open("GET",B,true);D.onreadystatechange=function(){if(D.readyState==4){if((D.status==200||D.status==0)){if(D.responseText){A.showFlashUI(D.responseText)}}else{if(console){console.log("PicLens Lite could not load the RSS Feed: "+B)}}}};D.send("")}catch(C){this.ARGS.loadFeedInFlash=true;this.showFlashUI("")}},meetsReqs:function(){if(this.DEBUG_NOFLASH){return false}var B=(this.FLASH_VER.major==0)&&this.BROWSER_IE;var A=swfobjlite.hasFlashPlayerVersion("9.0.28");return A||B},removeChildren:function(){this.REMOVE_TIMER_ID=0;if(this.LITE_BG_DIV!==null){document.body.removeChild(this.LITE_BG_DIV);this.LITE_BG_DIV=null}if(this.LITE_FG_DIV!==null){document.body.removeChild(this.LITE_FG_DIV);this.LITE_FG_DIV=null}},resizeFlashToFitPaddedBox:function(){var B=this.getFlash();if(B){var C=this.getPageSize();var A=C.w-this.HPAD*2;var D=C.h-this.VPAD*2;B.style.width=A;B.style.height=D;B.width=A;B.height=D}},resizeToFitPaddedBox:function(B,A){if(typeof A=="undefined"){A=this.getPageSize()}B.width=(A.w-this.HPAD*2)+"px";B.height=(A.h-this.VPAD*2)+"px"},resizeToPaddedBox:function(A){A.left=A.right=this.HPAD+"px";A.top=A.bottom=this.VPAD+"px"},resizeUI:function(){if(this.LITE_FG_DIV){var A=this.LITE_FG_DIV.style;this.resizeToPaddedBox(A);this.resizeToFitPaddedBox(A);this.resizeFlashToFitPaddedBox()}},setRunningFlag:function(A){this.LITE_IS_RUNNING=A;this.piclensIsRunning_=A},setResizeHandler:function(){if(!this.RESIZE_HANDLER_EXISTS&&this.BROWSER_SAF){var A=this;window.addEventListener("resize",function(){A.resizeUI()},false);this.RESIZE_HANDLER_EXISTS=true}},setResizeTimer:function(){if(this.BROWSER_IE6){this.RESIZE_TIMER_IE6=setInterval(function(){PicLensLite.autoResize()},1000)}},showFlashUI:function(A){this.THE_FEED=A;this.findScriptLocation();this.createBackgroundOverlay();this.createForegroundFlashComponent();if(this.BROWSER_IE){this.appendElementsToDocument()}this.injectFlashPlayer();if(!this.BROWSER_IE){this.appendElementsToDocument()}this.addKeyHandlers();this.addMouseHandlers();this.setRunningFlag(true);this.setResizeTimer();this.setResizeHandler();this.startLytebox()},sendMouseScrollToFlash:function(B){if(!this.isRunning()){return }var A=this.getFlash();if(A!=null&&A.fl_mouseMoved){A.fl_mouseMoved(B)}}};var swfobjlite=function(){var UNDEF="undefined",OBJECT="object",SHOCKWAVE_FLASH="Shockwave Flash",SHOCKWAVE_FLASH_AX="ShockwaveFlash.ShockwaveFlash",win=window,doc=document,nav=navigator;var ua=function(){var w3cdom=typeof doc.getElementById!=UNDEF&&typeof doc.getElementsByTagName!=UNDEF&&typeof doc.createElement!=UNDEF&&typeof doc.appendChild!=UNDEF&&typeof doc.replaceChild!=UNDEF&&typeof doc.removeChild!=UNDEF&&typeof doc.cloneNode!=UNDEF,playerVersion=[0,0,0],d=null;if(typeof nav.plugins!=UNDEF&&typeof nav.plugins[SHOCKWAVE_FLASH]==OBJECT){d=nav.plugins[SHOCKWAVE_FLASH].description;if(d){d=d.replace(/^.*\s+(\S+\s+\S+$)/,"$1");playerVersion[0]=parseInt(d.replace(/^(.*)\..*$/,"$1"),10);playerVersion[1]=parseInt(d.replace(/^.*\.(.*)\s.*$/,"$1"),10);playerVersion[2]=/r/.test(d)?parseInt(d.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof win.ActiveXObject!=UNDEF){var a=null,fp6Crash=false;try{a=new ActiveXObject(SHOCKWAVE_FLASH_AX+".7")}catch(e){try{a=new ActiveXObject(SHOCKWAVE_FLASH_AX+".6");playerVersion=[6,0,21];a.AllowScriptAccess="always"}catch(e){if(playerVersion[0]==6){fp6Crash=true}}if(!fp6Crash){try{a=new ActiveXObject(SHOCKWAVE_FLASH_AX)}catch(e){}}}if(!fp6Crash&&a){try{d=a.GetVariable("$version");if(d){d=d.split(" ")[1].split(",");playerVersion=[parseInt(d[0],10),parseInt(d[1],10),parseInt(d[2],10)]}}catch(e){}}}}var u=nav.userAgent.toLowerCase(),p=nav.platform.toLowerCase(),webkit=/webkit/.test(u)?parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,ie=false,windows=p?/win/.test(p):/win/.test(u),mac=p?/mac/.test(p):/mac/.test(u); +/*@cc_on + ie = true; + @if (@_win32) + windows = true; + @elif (@_mac) + mac = true; + @end + @*/ +return{w3cdom:w3cdom,pv:playerVersion,webkit:webkit,ie:ie,win:windows,mac:mac}}();return{hasFlashPlayerVersion:function(rv){var pv=ua.pv,v=rv.split(".");v[0]=parseInt(v[0],10);v[1]=parseInt(v[1],10);v[2]=parseInt(v[2],10);return(pv[0]>v[0]||(pv[0]==v[0]&&pv[1]>v[1])||(pv[0]==v[0]&&pv[1]==v[1]&&pv[2]>=v[2]))?true:false},getFlashPlayerVersion:function(){return{major:ua.pv[0],minor:ua.pv[1],release:ua.pv[2]}}}}();var BrowserDetect={init:function(){this.browser=this.searchString(this.dataBrowser)||"Unknown Browser";this.version=this.searchVersion(navigator.userAgent)||this.searchVersion(navigator.appVersion)||"Unknown Version";this.OS=this.searchString(this.dataOS)||"Unknown OS"},searchString:function(D){for(var A=0;A<D.length;A++){var B=D[A].string;var C=D[A].prop;this.versionSearchString=D[A].versionSearch||D[A].identity;if(B){if(B.indexOf(D[A].subString)!=-1){return D[A].identity}}else{if(C){return D[A].identity}}}},searchVersion:function(B){var A=B.indexOf(this.versionSearchString);if(A==-1){return }return parseFloat(B.substring(A+this.versionSearchString.length+1))},dataBrowser:[{string:navigator.userAgent,subString:"OmniWeb",versionSearch:"OmniWeb/",identity:"OmniWeb"},{string:navigator.vendor,subString:"Apple",identity:"Safari"},{prop:window.opera,identity:"Opera"},{string:navigator.vendor,subString:"iCab",identity:"iCab"},{string:navigator.vendor,subString:"KDE",identity:"Konqueror"},{string:navigator.userAgent,subString:"Firefox",identity:"Firefox"},{string:navigator.vendor,subString:"Camino",identity:"Camino"},{string:navigator.userAgent,subString:"Netscape",identity:"Netscape"},{string:navigator.userAgent,subString:"MSIE",identity:"Explorer",versionSearch:"MSIE"},{string:navigator.userAgent,subString:"Gecko",identity:"Mozilla",versionSearch:"rv"},{string:navigator.userAgent,subString:"Mozilla",identity:"Netscape",versionSearch:"Mozilla"}],dataOS:[{string:navigator.platform,subString:"Win",identity:"Windows"},{string:navigator.platform,subString:"Mac",identity:"Mac"},{string:navigator.platform,subString:"Linux",identity:"Linux"}]};BrowserDetect.init(); \ No newline at end of file diff --git a/plugins/tidypics/vendors/jquery.imgareaselect-0.7.js b/plugins/tidypics/vendors/jquery.imgareaselect-0.7.js new file mode 100644 index 0000000000000000000000000000000000000000..3adac1d6ab940a98b946a835332ac804df275220 --- /dev/null +++ b/plugins/tidypics/vendors/jquery.imgareaselect-0.7.js @@ -0,0 +1,614 @@ +/* + * imgAreaSelect jQuery plugin + * version 0.7 + * + * Copyright (c) 2008-2009 Michal Wojciechowski (odyniec.net) + * + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://odyniec.net/projects/imgareaselect/ + * + */ + +jQuery.imgAreaSelect = { onKeyPress: null }; + +jQuery.imgAreaSelect.init = function (img, options) { + var $img = jQuery(img), $area = jQuery('<div />'), + $border1 = jQuery('<div />'), $border2 = jQuery('<div />'), + $areaOver = jQuery('<div />'), $areaOver2, + $outLeft = jQuery('<div />'), $outTop = jQuery('<div />'), + $outRight = jQuery('<div />'), $outBottom = jQuery('<div />'), + $handles, handleWidth, handles = [ ], + left, top, imgOfs, imgWidth, imgHeight, parent, parOfs, parScroll, + zIndex = 0, position = 'absolute', $p, startX, startY, moveX, moveY, + resizeMargin = 10, resize = [ ], V = 0, H = 1, + keyDown, d, aspectRatio, x1, x2, y1, y2, x, y, adjusted, + selection = { x1: 0, y1: 0, x2: 0, y2: 0, width: 0, height: 0 }; + + var $a = $area.add($border1).add($border2).add($areaOver); + var $o = $outLeft.add($outTop).add($outRight).add($outBottom); + + function viewX(x) + { + return x + imgOfs.left + parScroll.left - parOfs.left; + } + + function viewY(y) + { + return y + imgOfs.top + parScroll.top - parOfs.top; + } + + function selX(x) + { + return x - imgOfs.left - parScroll.left + parOfs.left; + } + + function selY(y) + { + return y - imgOfs.top - parScroll.top + parOfs.top; + } + + function evX(event) + { + return event.pageX + parScroll.left - parOfs.left; + } + + function evY(event) + { + return event.pageY + parScroll.top - parOfs.top; + } + + function getZIndex() + { + $p = $img; + + while ($p.length && !$p.is('body')) { + if (!isNaN($p.css('z-index')) && $p.css('z-index') > zIndex) + zIndex = $p.css('z-index'); + if ($p.css('position') == 'fixed') + position = 'fixed'; + + $p = $p.parent(); + } + } + + function adjust() + { + imgOfs = $img.offset(); + imgOfs.left = parseInt(imgOfs.left) + parseInt($img.css("border-left-width")) + parseInt($img.css("padding-left")); + imgOfs.top = parseInt(imgOfs.top) + parseInt($img.css("border-top-width")) + parseInt($img.css("padding-top")); + imgWidth = $img.width(); + imgHeight = $img.height(); + + if (jQuery(parent).is('body')) + parOfs = parScroll = { left: 0, top: 0 }; + else { + parOfs = jQuery(parent).offset(); + parScroll = { left: parent.scrollLeft, top: parent.scrollTop }; + } + + left = viewX(0); + top = viewY(0); + } + + function update(resetKeyPress) + { + $a.css({ + left: viewX(selection.x1) + 'px', + top: viewY(selection.y1) + 'px', + width: Math.max(selection.width - options.borderWidth * 2, 0) + 'px', + height: Math.max(selection.height - options.borderWidth * 2, 0) + 'px' + }); + $areaOver.css({ width: selection.width + 'px', height: selection.height + 'px' }); + $outLeft.css({ left: left + 'px', top: top + 'px', + width: selection.x1 + 'px', height: imgHeight + 'px' }); + $outTop.css({ left: left + selection.x1 + 'px', top: top + 'px', + width: selection.width + 'px', height: selection.y1 + 'px' }); + $outRight.css({ left: left + selection.x2 + 'px', top: top + 'px', + width: imgWidth - selection.x2 + 'px', height: imgHeight + 'px' }); + $outBottom.css({ left: left + selection.x1 + 'px', top: top + selection.y2 + 'px', + width: selection.width + 'px', height: imgHeight - selection.y2 + 'px' }); + + if ($handles) { + handles[0].css({ left: viewX(selection.x1) + 'px', + top: viewY(selection.y1) + 'px' }); + handles[1].css({ left: viewX(selection.x2 - handleWidth) + 'px', + top: viewY(selection.y1) + 'px' }); + handles[2].css({ left: viewX(selection.x1) + 'px', + top: viewY(selection.y2 - handleWidth) + 'px' }); + handles[3].css({ left: viewX(selection.x2 - handleWidth) + 'px', + top: viewY(selection.y2 - handleWidth) + 'px' }); + + if (handles.length == 8) { + handles[4].css({ left: viewX(selection.x1 + (selection.width - + handleWidth) / 2) + 'px', top: viewY(selection.y1) + 'px' }); + handles[5].css({ left: viewX(selection.x1) + 'px', top: + viewY(selection.y1 + (selection.height - handleWidth) / 2) + 'px' }); + handles[6].css({ left: viewX(selection.x1 + (selection.width - handleWidth) + / 2) + 'px', top: viewY(selection.y2 - handleWidth) + 'px' }); + handles[7].css({ left: viewX(selection.x2 - handleWidth) + 'px', top: + viewY(selection.y1 + (selection.height - handleWidth) / 2) + 'px' }); + } + + for (var i = 0; i < handles.length; i++) { + if (selX(parseInt(handles[i].css('left'))) < 0) + handles[i].css('left', viewX(0) + 'px'); + if (selX(parseInt(handles[i].css('left'))) > imgWidth - handleWidth) + handles[i].css('left', viewX(imgWidth - handleWidth) + 'px'); + if (selY(parseInt(handles[i].css('top'))) < 0) + handles[i].css('top', viewY(0) + 'px'); + if (selY(parseInt(handles[i].css('top'))) > imgHeight - handleWidth) + handles[i].css('top', viewY(imgHeight - handleWidth) + 'px'); + } + } + + if (resetKeyPress !== false) { + if (jQuery.imgAreaSelect.keyPress != docKeyPress) + jQuery(document).unbind(jQuery.imgAreaSelect.keyPress, + jQuery.imgAreaSelect.onKeyPress); + + if (options.keys) + jQuery(document).bind(jQuery.imgAreaSelect.keyPress, + jQuery.imgAreaSelect.onKeyPress = docKeyPress); + } + } + + function areaMouseMove(event) + { + if (!adjusted) { + adjust(); + adjusted = true; + + $a.one('mouseout', function () { adjusted = false; }); + } + + x = selX(evX(event)) - selection.x1; + y = selY(evY(event)) - selection.y1; + + resize = [ ]; + + if (options.resizable) { + if (y <= resizeMargin) + resize[V] = 'n'; + else if (y >= selection.height - resizeMargin) + resize[V] = 's'; + if (x <= resizeMargin) + resize[H] = 'w'; + else if (x >= selection.width - resizeMargin) + resize[H] = 'e'; + } + + $areaOver.css('cursor', resize.length ? resize.join('') + '-resize' : + options.movable ? 'move' : ''); + if ($areaOver2) + $areaOver2.toggle(); + } + + function areaMouseDown(event) + { + if (event.which != 1) return false; + + adjust(); + + if (options.resizable && resize.length > 0) { + jQuery('body').css('cursor', resize.join('') + '-resize'); + + x1 = viewX(selection[resize[H] == 'w' ? 'x2' : 'x1']); + y1 = viewY(selection[resize[V] == 'n' ? 'y2' : 'y1']); + + jQuery(document).mousemove(selectingMouseMove); + $areaOver.unbind('mousemove', areaMouseMove); + + jQuery(document).one('mouseup', function () { + resize = [ ]; + + jQuery('body').css('cursor', ''); + + if (options.autoHide || selection.width == 0 || selection.height == 0) + $a.add($o).add($handles).hide(); + + options.onSelectEnd(img, selection); + + jQuery(document).unbind('mousemove', selectingMouseMove); + $areaOver.mousemove(areaMouseMove); + }); + } + else if (options.movable) { + moveX = selection.x1 + left; + moveY = selection.y1 + top; + startX = evX(event); + startY = evY(event); + + $areaOver.unbind('mousemove', areaMouseMove); + + jQuery(document).mousemove(movingMouseMove) + .one('mouseup', function () { + options.onSelectEnd(img, selection); + + jQuery(document).unbind('mousemove', movingMouseMove); + $areaOver.mousemove(areaMouseMove); + }); + } + else + $img.mousedown(event); + + return false; + } + + function aspectRatioXY() + { + x2 = Math.max(left, Math.min(left + imgWidth, + x1 + Math.abs(y2 - y1) * aspectRatio * (x2 >= x1 ? 1 : -1))); + y2 = Math.round(Math.max(top, Math.min(top + imgHeight, + y1 + Math.abs(x2 - x1) / aspectRatio * (y2 >= y1 ? 1 : -1)))); + x2 = Math.round(x2); + } + + function aspectRatioYX() + { + y2 = Math.max(top, Math.min(top + imgHeight, + y1 + Math.abs(x2 - x1) / aspectRatio * (y2 >= y1 ? 1 : -1))); + x2 = Math.round(Math.max(left, Math.min(left + imgWidth, + x1 + Math.abs(y2 - y1) * aspectRatio * (x2 >= x1 ? 1 : -1)))); + y2 = Math.round(y2); + } + + function doResize(newX2, newY2) + { + x2 = newX2; + y2 = newY2; + + if (options.minWidth && Math.abs(x2 - x1) < options.minWidth) { + x2 = x1 - options.minWidth * (x2 < x1 ? 1 : -1); + + if (x2 < left) + x1 = left + options.minWidth; + else if (x2 > left + imgWidth) + x1 = left + imgWidth - options.minWidth; + } + + if (options.minHeight && Math.abs(y2 - y1) < options.minHeight) { + y2 = y1 - options.minHeight * (y2 < y1 ? 1 : -1); + + if (y2 < top) + y1 = top + options.minHeight; + else if (y2 > top + imgHeight) + y1 = top + imgHeight - options.minHeight; + } + + x2 = Math.max(left, Math.min(x2, left + imgWidth)); + y2 = Math.max(top, Math.min(y2, top + imgHeight)); + + if (aspectRatio) + if (Math.abs(x2 - x1) / aspectRatio > Math.abs(y2 - y1)) + aspectRatioYX(); + else + aspectRatioXY(); + + if (options.maxWidth && Math.abs(x2 - x1) > options.maxWidth) { + x2 = x1 - options.maxWidth * (x2 < x1 ? 1 : -1); + if (aspectRatio) aspectRatioYX(); + } + + if (options.maxHeight && Math.abs(y2 - y1) > options.maxHeight) { + y2 = y1 - options.maxHeight * (y2 < y1 ? 1 : -1); + if (aspectRatio) aspectRatioXY(); + } + + selection = { x1: selX(Math.min(x1, x2)), x2: selX(Math.max(x1, x2)), + y1: selY(Math.min(y1, y2)), y2: selY(Math.max(y1, y2)), + width: Math.abs(x2 - x1), height: Math.abs(y2 - y1) }; + + update(); + + options.onSelectChange(img, selection); + } + + function selectingMouseMove(event) + { + x2 = !resize.length || resize[H] || aspectRatio ? evX(event) : viewX(selection.x2); + y2 = !resize.length || resize[V] || aspectRatio ? evY(event) : viewY(selection.y2); + + doResize(x2, y2); + + return false; + } + + function doMove(newX1, newY1) + { + x2 = (x1 = newX1) + selection.width; + y2 = (y1 = newY1) + selection.height; + + selection.x1 = selX(x1); + selection.y1 = selY(y1); + selection.x2 = selX(x2); + selection.y2 = selY(y2); + + update(); + + options.onSelectChange(img, selection); + } + + function movingMouseMove(event) + { + var newX1 = Math.max(left, Math.min(moveX + evX(event) - startX, + left + imgWidth - selection.width)); + var newY1 = Math.max(top, Math.min(moveY + evY(event) - startY, + top + imgHeight - selection.height)); + + doMove(newX1, newY1); + + event.preventDefault(); + return false; + } + + function startSelection(event) + { + adjust(); + + selection = { x1: selX(x1), y1: selY(y1) }; + doResize(x1, y1); + + resize = [ ]; + + $a.add($o).add($handles).show(); + + jQuery(document).unbind('mouseup', cancelSelection) + .mousemove(selectingMouseMove); + $areaOver.unbind('mousemove', areaMouseMove); + + options.onSelectStart(img, selection); + + jQuery(document).one('mouseup', function () { + if (options.autoHide || (selection.width * selection.height == 0)) + $a.add($o).add($handles).hide(); + + options.onSelectEnd(img, selection); + + jQuery(document).unbind('mousemove', selectingMouseMove); + $areaOver.mousemove(areaMouseMove); + }); + } + + function cancelSelection() + { + jQuery(document).unbind('mousemove', startSelection); + $a.add($o).add($handles).hide(); + + selection = { x1: 0, y1: 0, x2: 0, y2: 0, width: 0, height: 0 }; + + options.onSelectChange(img, selection); + options.onSelectEnd(img, selection); + } + + function imgMouseDown(event) + { + if (event.which != 1) return false; + + startX = x1 = evX(event); + startY = y1 = evY(event); + + jQuery(document).one('mousemove', startSelection) + .one('mouseup', cancelSelection); + + return false; + } + + function windowResize() + { + adjust(); + update(false); + x1 = viewX(selection.x1); + y1 = viewY(selection.y1); + x2 = viewX(selection.x2); + y2 = viewY(selection.y2); + } + + var docKeyPress = function(event) { + var k = options.keys, d = 10, t, + key = event.keyCode || event.which; + + if (!isNaN(k.arrows)) d = k.arrows; + if (!isNaN(k.shift) && event.shiftKey) d = k.shift; + if (!isNaN(k.ctrl) && event.ctrlKey) d = k.ctrl; + if (!isNaN(k.alt) && (event.altKey || event.originalEvent.altKey)) d = k.alt; + + if (k.arrows == 'resize' || (k.shift == 'resize' && event.shiftKey) || + (k.ctrl == 'resize' && event.ctrlKey) || + (k.alt == 'resize' && (event.altKey || event.originalEvent.altKey))) + { + switch (key) { + case 37: + d = -d; + case 39: + t = Math.max(x1, x2); + x1 = Math.min(x1, x2); + x2 = Math.max(t + d, x1); + if (aspectRatio) aspectRatioYX(); + break; + case 38: + d = -d; + case 40: + t = Math.max(y1, y2); + y1 = Math.min(y1, y2); + y2 = Math.max(t + d, y1); + if (aspectRatio) aspectRatioXY(); + break; + default: + return; + } + + doResize(x2, y2); + } + else { + x1 = Math.min(x1, x2); + y1 = Math.min(y1, y2); + + switch (key) { + case 37: + doMove(Math.max(x1 - d, left), y1); + break; + case 38: + doMove(x1, Math.max(y1 - d, top)); + break; + case 39: + doMove(x1 + Math.min(d, imgWidth - selX(x2)), y1); + break; + case 40: + doMove(x1, y1 + Math.min(d, imgHeight - selY(y2))); + break; + default: + return; + } + } + + return false; + }; + + this.setOptions = function(newOptions) + { + options = jQuery.extend(options, newOptions); + + if (newOptions.x1 != null) { + selection = { x1: newOptions.x1, y1: newOptions.y1, + x2: newOptions.x2, y2: newOptions.y2 }; + newOptions.show = true; + } + + if (newOptions.keys) + options.keys = jQuery.extend({ shift: 1, ctrl: 'resize' }, + newOptions.keys === true ? { } : newOptions.keys); + + parent = jQuery(options.parent).get(0); + + adjust(); + + getZIndex(); + + x1 = viewX(selection.x1); + y1 = viewY(selection.y1); + x2 = viewX(selection.x2); + y2 = viewY(selection.y2); + selection.width = x2 - x1; + selection.height = y2 - y1; + + if ($handles) { + $handles.remove(); + $handles = null; + handles = [ ]; + } + + if (options.handles) { + for (var i = 0; i < (options.handles == 'corners' ? 4 : 8); i++) + $handles = $handles ? $handles.add(handles[i] = jQuery('<div />')) : + handles[i] = jQuery('<div />'); + + handleWidth = 4 + options.borderWidth; + + $handles.css({ position: position, borderWidth: options.borderWidth, + borderStyle: 'solid', borderColor: options.borderColor1, + backgroundColor: options.borderColor2, display: $area.css('display'), + width: handleWidth + 'px', height: handleWidth + 'px', + fontSize: '0px', zIndex: zIndex > 0 ? zIndex + 1 : '1' }); + $handles.addClass(options.classPrefix + '-handle'); + + handleWidth += options.borderWidth * 2; + } + + $o.addClass(options.classPrefix + '-outer'); + $area.addClass(options.classPrefix + '-selection'); + $border1.addClass(options.classPrefix + '-border1'); + $border2.addClass(options.classPrefix + '-border2'); + + $a.css({ borderWidth: options.borderWidth + 'px' }); + $area.css({ backgroundColor: options.selectionColor, opacity: options.selectionOpacity }); + $border1.css({ borderStyle: 'solid', borderColor: options.borderColor1 }); + $border2.css({ borderStyle: 'dashed', borderColor: options.borderColor2 }); + $o.css({ opacity: options.outerOpacity, backgroundColor: options.outerColor }); + + jQuery(options.parent).append($o.add($a).add($handles)); + + update(); + + if (newOptions.hide) + $a.add($o).add($handles).hide(); + else if (newOptions.show) + $a.add($o).add($handles).show(); + + aspectRatio = options.aspectRatio && (d = options.aspectRatio.split(/:/)) ? + d[0] / d[1] : null; + + if (aspectRatio) + if (options.minWidth) + options.minHeight = parseInt(options.minWidth / aspectRatio); + else if (options.minHeight) + options.minWidth = parseInt(options.minHeight * aspectRatio); + + if (options.disable || options.enable === false) { + $areaOver.unbind('mousemove', areaMouseMove).unbind('mousedown', areaMouseDown); + $img.add($o).unbind('mousedown', imgMouseDown); + jQuery(window).unbind('resize', windowResize); + } + else if (options.enable || options.disable === false) { + if (options.resizable || options.movable) + $areaOver.mousemove(areaMouseMove).mousedown(areaMouseDown); + + if (!options.persistent) + $img.add($o).mousedown(imgMouseDown); + jQuery(window).resize(windowResize); + } + + options.enable = options.disable = undefined; + }; + + if (jQuery.browser.msie) + $img.attr('unselectable', 'on'); + + jQuery.imgAreaSelect.keyPress = jQuery.browser.msie || + jQuery.browser.safari ? 'keydown' : 'keypress'; + + if (jQuery.browser.opera) + $areaOver.append($areaOver2 = jQuery('<div style="width: 100%; height: 100%;" />')); + + getZIndex(); + + $a.add($o).css({ display: 'none', position: position, + overflow: 'hidden', zIndex: zIndex > 0 ? zIndex : '0' }); + $areaOver.css({ zIndex: zIndex > 0 ? zIndex + 2 : '2' }); + $area.css({ borderStyle: 'solid' }); + + this.setOptions(options = jQuery.extend({ + borderColor1: '#000', + borderColor2: '#fff', + borderWidth: 1, + classPrefix: 'imgareaselect', + movable: true, + resizable: true, + selectionColor: '#fff', + selectionOpacity: 0.2, + outerColor: '#000', + outerOpacity: 0.2, + parent: 'body', + onSelectStart: function () {}, + onSelectChange: function () {}, + onSelectEnd: function () {} + }, options)); +}; + +jQuery.fn.imgAreaSelect = function (options) { + options = options || {}; + + this.each(function () { + if (jQuery(this).data('imgAreaSelect')) + jQuery(this).data('imgAreaSelect').setOptions(options); + else { + if (options.enable === undefined && options.disable === undefined) + options.enable = true; + + jQuery(this).data('imgAreaSelect', new jQuery.imgAreaSelect.init(this, options)); + } + }); + + return this; +}; diff --git a/plugins/tidypics/vendors/jquery.quicksearch.js b/plugins/tidypics/vendors/jquery.quicksearch.js new file mode 100644 index 0000000000000000000000000000000000000000..700872bce252e2e9dfc211338a41554f557de2e9 --- /dev/null +++ b/plugins/tidypics/vendors/jquery.quicksearch.js @@ -0,0 +1,347 @@ +jQuery(function ($) { + $.fn.quicksearch = function (opt) { + + function is_empty(i) + { + return (i === null || i === undefined || i === false) ? true: false; + } + + function strip_html(input) + { + var regexp = new RegExp(/\<[^\<]+\>/g); + var output = input.replace(regexp, ""); + output = $.trim(output.toLowerCase().replace(/\n/, '').replace(/\s{2,}/, ' ')); + return output; + } + + function get_key() + { + var input = strip_html($('input[rel="' + options.randomElement + '"]').val()); + + if (input.indexOf(' ') === -1) + { + return input; + } + else + { + return input.split(" "); + } + } + + function test_key(k, value, type) + { + if (type === "string") + { + return test_key_string(k, value); + } + else + { + return test_key_arr(k, value); + } + } + + function test_key_string(k, value) + { + return (value.indexOf(k) > -1); + } + + function test_key_arr(k, value) + { + for (var i = 0; i < k.length; i++) { + var test = value.indexOf(k[i]); + if (test === -1) { + return false; + } + } + return true; + } + + function select_element(el) + { + if (options.hideElement === "grandparent") + { + return $(el).parent().parent(); + } + else if (options.hideElement === "parent") + { + return $(el).parent(); + } + else + { + return $(el); + } + } + + function stripe(el) + { + if (doStripe) + { + var i = 0; + select_element(el).filter(':visible').each(function () { + + for (var j = 0; j < stripeRowLength; j++) + { + if (i === j) + { + $(this).addClass(options.stripeRowClass[i]); + + } + else + { + $(this).removeClass(options.stripeRowClass[j]); + } + } + i = (i + 1) % stripeRowLength; + }); + } + } + + function fix_widths(el) + { + $(el).find('td').each(function () { + $(this).attr('width', parseInt($(this).css('width'))); + }); + } + + function loader(o) { + if (options.loaderId) + { + var l = $('input[rel="' + options.randomElement + '"]').parent().find('.loader'); + if (o === 'hide') + { + l.hide(); + } + else + { + l.show(); + } + } + } + + function place_form() { + var formPosition = options.position; + var formAttached = options.attached; + + if (formPosition === 'before') { + $(formAttached).before(make_form()); + } else if (formPosition === 'prepend') { + $(formAttached).prepend(make_form()); + } else if (formPosition === 'append') { + $(formAttached).append(make_form()); + } else { + $(formAttached).after(make_form()); + } + } + + function make_form_label() + { +/* + if (!is_empty(options.labelText)) { + return '<label for="' + options.randomElement + '" '+ + 'class="' + options.labelClass + '">' + + options.labelText + + '</label> '; + } +*/ + return ''; + } + + function make_form_input() + { + var val = (!is_empty(options.inputText)) ? options.inputText : "" + return '<input type="text" value="' + val + '" rel="' + options.randomElement + '" class="' + options.inputClass + '" id="' + options.randomElement + '" /> '; + } + + function make_form_loader() + { + if (!is_empty(options.loaderImg)) { + return '<img src="' + options.loaderImg + '" alt="Loading" id="' + options.loaderId + '" class="' + options.loaderClass + '" />'; + } else { + return '<span id="' + options.loaderId + '" class="' + options.loaderClass + '">' + options.loaderText + '</span>'; + } + } + + function make_form() + { + var f = (!options.isFieldset) ? 'form' : 'fieldset'; + /*return '<' + f + ' action="#" ' + 'id="'+ options.formId + '" ' + 'class="quicksearch">' + + make_form_label() + make_form_input() + make_form_loader() + + '</' + f + '>';*/ + return make_form_label() + make_form_input() + make_form_loader() + } + + function focus_on_load() + { + $('input[rel="' + options.randomElement + '"]').get(0).focus(); + } + + function toggle_text() { + $('input[rel="' + options.randomElement + '"]').focus(function () { + if ($(this).val() === options.inputText) { + $(this).val(''); + } + }); + $('input[rel="' + options.randomElement + '"]').blur(function () { + if ($(this).val() === "") { + $(this).val(options.inputText); + } + }); + } + + function get_cache(el) + { + return $(el).map(function(){ + return strip_html(this.innerHTML); + }); + } + + function init() + { + place_form(); + if (options.fixWidths) fix_widths(el); + if (options.focusOnLoad) focus_on_load(); + if (options.inputText != "" && options.inputText != null) toggle_text(); + + cache = get_cache(el); + + stripe(el); + loader('hide'); + } + + function qs() + { + clearTimeout(timeout); + timeout = setTimeout(function () { + + loader('show'); + + setTimeout(function () { + options.onBefore(); + + var k = get_key(); + var k_type = (typeof k); + var i = 0; + + k = options.filter(k); + + if (k != "") + { + if (typeof score[k] === "undefined") + { + score[k] = new Array(); + cache.each(function (i) { + if (test_key(k, cache[i], k_type)) + { + score[k][i] = true; + } + }); + } + + if (score[k].length === 0) + { + select_element(el).hide(); + } + else + { + /*console.log(score[k].length); + if(score[k].length==1) + { + //$(el).parents('ul').find('li:visible:eq(0) a').addClass('selected'); + } + else + { + //$(el).parents('ul').find('li:visible:eq(0) a').removeClass('selected') + }*/ + + $(el).each(function (i) { + if (score[k][i]) + { + select_element(this).show(); + } + else + { + select_element(this).hide(); + } + } + ); + + if($(el).parents('ul').find('li:visible').length==1) + $(el).parents('ul').find('li:visible:eq(0) a').addClass('selected'); + else + $(el).parents('ul').find('li:visible:eq(0) a').removeClass('selected'); + + } + } + else + { + select_element(el).show(); + } + + stripe(el); + }, options.delay/2); + + setTimeout( function () { + loader('hide'); + }, options.delay/2); + + options.onAfter(); + + }, options.delay/2); + } + + var options = $.extend({ + position: 'prepend', + attached: 'body', + formId: 'quicksearch', + labelText: 'Quick Search', + labelClass: 'qs_label', + inputText: null, + inputClass: 'qs_input', + loaderId: 'loader', + loaderClass: 'loader', + loaderImg: null, + loaderText: 'Loading...', + stripeRowClass: null, + hideElement: null, + delay: 500, + focusOnLoad: false, + onBefore: function () { }, + onAfter: function () { }, + filter: function (i) { + return i; + }, + randomElement: 'qs' + Math.floor(Math.random() * 1000000), + isFieldset: false, + fixWidths: false + }, opt); + + var timeout; + var score = {}; + var stripeRowLength = (!is_empty(options.stripeRowClass)) ? options.stripeRowClass.length : 0; + var doStripe = (stripeRowLength > 0) ? true : false; + var el = this; + var cache; + var selector = $(this).selector; + + $.fn.extend({ + reset_cache: function () { + el = $(selector); + cache = get_cache(el); + } + }); + + init(); + + $('input[rel="' + options.randomElement + '"]').keydown(function (e) { + var keycode = e.keyCode; + if (!(keycode === 9 || keycode === 13 || keycode === 16 || keycode === 17 || keycode === 18 || keycode === 38 || keycode === 40 || keycode === 224)) + { + qs(); + } + }); + + //$('#quicksearch').submit( function () { addTag()}); + + return this; + }; +}); \ No newline at end of file diff --git a/plugins/tidypics/vendors/lytebox/images/blank.gif b/plugins/tidypics/vendors/lytebox/images/blank.gif new file mode 100644 index 0000000000000000000000000000000000000000..1d11fa9ada9e93505b3d736acb204083f45d5fbf Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/blank.gif differ diff --git a/plugins/tidypics/vendors/lytebox/images/close_blue.png b/plugins/tidypics/vendors/lytebox/images/close_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..297368c821c5cf9fa2f9ec3294a3ff4410238667 Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/close_blue.png differ diff --git a/plugins/tidypics/vendors/lytebox/images/close_gold.png b/plugins/tidypics/vendors/lytebox/images/close_gold.png new file mode 100644 index 0000000000000000000000000000000000000000..d1b847694285ee99bead9f76ced1fe468c92ff66 Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/close_gold.png differ diff --git a/plugins/tidypics/vendors/lytebox/images/close_green.png b/plugins/tidypics/vendors/lytebox/images/close_green.png new file mode 100644 index 0000000000000000000000000000000000000000..83909e2d766a2002e239a69fb0a7ed2e1dc74b9e Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/close_green.png differ diff --git a/plugins/tidypics/vendors/lytebox/images/close_grey.png b/plugins/tidypics/vendors/lytebox/images/close_grey.png new file mode 100644 index 0000000000000000000000000000000000000000..bc83ac55ef79ac1f8e27c8cdd8b2fba16cf2de8c Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/close_grey.png differ diff --git a/plugins/tidypics/vendors/lytebox/images/close_red.png b/plugins/tidypics/vendors/lytebox/images/close_red.png new file mode 100644 index 0000000000000000000000000000000000000000..3d835bb305b2ebcf9a876055d53a8a0aef7623b4 Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/close_red.png differ diff --git a/plugins/tidypics/vendors/lytebox/images/loading.gif b/plugins/tidypics/vendors/lytebox/images/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..f864d5fd38b7466c76b5a36dc0e3e9455c0126e2 Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/loading.gif differ diff --git a/plugins/tidypics/vendors/lytebox/images/next_blue.gif b/plugins/tidypics/vendors/lytebox/images/next_blue.gif new file mode 100644 index 0000000000000000000000000000000000000000..4666e44d3555af0c91cf467c1a94d229fd3d5cf6 Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/next_blue.gif differ diff --git a/plugins/tidypics/vendors/lytebox/images/next_gold.gif b/plugins/tidypics/vendors/lytebox/images/next_gold.gif new file mode 100644 index 0000000000000000000000000000000000000000..c5ba21f5cf44fd06e65d30739e06c3087b2c2925 Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/next_gold.gif differ diff --git a/plugins/tidypics/vendors/lytebox/images/next_green.gif b/plugins/tidypics/vendors/lytebox/images/next_green.gif new file mode 100644 index 0000000000000000000000000000000000000000..85a1433b83d52854dd7b968c66e05e12a7da37fd Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/next_green.gif differ diff --git a/plugins/tidypics/vendors/lytebox/images/next_grey.gif b/plugins/tidypics/vendors/lytebox/images/next_grey.gif new file mode 100644 index 0000000000000000000000000000000000000000..f1773cd195fe982a3e7911d3ff09cc6c21885a6c Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/next_grey.gif differ diff --git a/plugins/tidypics/vendors/lytebox/images/next_red.gif b/plugins/tidypics/vendors/lytebox/images/next_red.gif new file mode 100644 index 0000000000000000000000000000000000000000..4ddff3daec5c54af69221f9c082172f5ec21f74f Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/next_red.gif differ diff --git a/plugins/tidypics/vendors/lytebox/images/pause_blue.png b/plugins/tidypics/vendors/lytebox/images/pause_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..3d4e34f689a96db7b6911bddcaeff8aeedea1777 Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/pause_blue.png differ diff --git a/plugins/tidypics/vendors/lytebox/images/pause_gold.png b/plugins/tidypics/vendors/lytebox/images/pause_gold.png new file mode 100644 index 0000000000000000000000000000000000000000..ee529699c446ee5c2564745088bf695e8349ba5b Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/pause_gold.png differ diff --git a/plugins/tidypics/vendors/lytebox/images/pause_green.png b/plugins/tidypics/vendors/lytebox/images/pause_green.png new file mode 100644 index 0000000000000000000000000000000000000000..c52f28c1c4e16760ab62c7c356fb6a38dd50b9ed Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/pause_green.png differ diff --git a/plugins/tidypics/vendors/lytebox/images/pause_grey.png b/plugins/tidypics/vendors/lytebox/images/pause_grey.png new file mode 100644 index 0000000000000000000000000000000000000000..1c2e9e0b21e58eeecd289d94cc5ee561fb3ee16e Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/pause_grey.png differ diff --git a/plugins/tidypics/vendors/lytebox/images/pause_red.png b/plugins/tidypics/vendors/lytebox/images/pause_red.png new file mode 100644 index 0000000000000000000000000000000000000000..5ee4dcf5cf5b4292a865332a6f4ee4280c42a2c8 Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/pause_red.png differ diff --git a/plugins/tidypics/vendors/lytebox/images/play_blue.png b/plugins/tidypics/vendors/lytebox/images/play_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..c8cd259c46fc4574b987823d88b6507ee8a7c63e Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/play_blue.png differ diff --git a/plugins/tidypics/vendors/lytebox/images/play_gold.png b/plugins/tidypics/vendors/lytebox/images/play_gold.png new file mode 100644 index 0000000000000000000000000000000000000000..766d6513cef1102218a69434dee315866e166b3f Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/play_gold.png differ diff --git a/plugins/tidypics/vendors/lytebox/images/play_green.png b/plugins/tidypics/vendors/lytebox/images/play_green.png new file mode 100644 index 0000000000000000000000000000000000000000..6e832a43872ab925516109007c12cf1de141819e Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/play_green.png differ diff --git a/plugins/tidypics/vendors/lytebox/images/play_grey.png b/plugins/tidypics/vendors/lytebox/images/play_grey.png new file mode 100644 index 0000000000000000000000000000000000000000..8e18760be80a81e21a4864b48f3452e3de7c4057 Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/play_grey.png differ diff --git a/plugins/tidypics/vendors/lytebox/images/play_red.png b/plugins/tidypics/vendors/lytebox/images/play_red.png new file mode 100644 index 0000000000000000000000000000000000000000..887d6449648072b7f85bc494c838323cf2c093e1 Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/play_red.png differ diff --git a/plugins/tidypics/vendors/lytebox/images/prev_blue.gif b/plugins/tidypics/vendors/lytebox/images/prev_blue.gif new file mode 100644 index 0000000000000000000000000000000000000000..beba13ef5e1748d02b4cfb88f2ead310fdf06405 Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/prev_blue.gif differ diff --git a/plugins/tidypics/vendors/lytebox/images/prev_gold.gif b/plugins/tidypics/vendors/lytebox/images/prev_gold.gif new file mode 100644 index 0000000000000000000000000000000000000000..b481932586c7b5324160b79bd3f18bc2a1b26962 Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/prev_gold.gif differ diff --git a/plugins/tidypics/vendors/lytebox/images/prev_green.gif b/plugins/tidypics/vendors/lytebox/images/prev_green.gif new file mode 100644 index 0000000000000000000000000000000000000000..2d4e14e5230de53ac80a9c0a874b584f1ca0020b Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/prev_green.gif differ diff --git a/plugins/tidypics/vendors/lytebox/images/prev_grey.gif b/plugins/tidypics/vendors/lytebox/images/prev_grey.gif new file mode 100644 index 0000000000000000000000000000000000000000..a7f2260a56877db4e24dae5e09072dbc7e2c75b2 Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/prev_grey.gif differ diff --git a/plugins/tidypics/vendors/lytebox/images/prev_red.gif b/plugins/tidypics/vendors/lytebox/images/prev_red.gif new file mode 100644 index 0000000000000000000000000000000000000000..f702e6333684923a099633f2d8af55cfd928bc6b Binary files /dev/null and b/plugins/tidypics/vendors/lytebox/images/prev_red.gif differ diff --git a/plugins/tidypics/vendors/lytebox/lytebox.css b/plugins/tidypics/vendors/lytebox/lytebox.css new file mode 100644 index 0000000000000000000000000000000000000000..5303fac1bf364137015b95d7ee61a3b9c88411f2 --- /dev/null +++ b/plugins/tidypics/vendors/lytebox/lytebox.css @@ -0,0 +1,93 @@ +#lbOverlay { position: fixed; top: 0; left: 0; z-index: 99998; width: 100%; height: 500px; } + #lbOverlay.grey { background-color: #000000; } + #lbOverlay.red { background-color: #330000; } + #lbOverlay.green { background-color: #003300; } + #lbOverlay.blue { background-color: #011D50; } + #lbOverlay.gold { background-color: #666600; } + +#lbMain { position: absolute; left: 0; width: 100%; z-index: 99999; text-align: center; line-height: 0; } +#lbMain a img { border: none; } + +#lbOuterContainer { position: relative; background-color: #fff; width: 200px; height: 200px; margin: 0 auto; } + #lbOuterContainer.grey { border: 3px solid #888888; } + #lbOuterContainer.red { border: 3px solid #DD0000; } + #lbOuterContainer.green { border: 3px solid #00B000; } + #lbOuterContainer.blue { border: 3px solid #5F89D8; } + #lbOuterContainer.gold { border: 3px solid #B0B000; } + +#lbDetailsContainer { font: 10px Verdana, Helvetica, sans-serif; background-color: #fff; width: 100%; line-height: 1.4em; overflow: auto; margin: 0 auto; } + #lbDetailsContainer.grey { border: 3px solid #888888; border-top: none; } + #lbDetailsContainer.red { border: 3px solid #DD0000; border-top: none; } + #lbDetailsContainer.green { border: 3px solid #00B000; border-top: none; } + #lbDetailsContainer.blue { border: 3px solid #5F89D8; border-top: none; } + #lbDetailsContainer.gold { border: 3px solid #B0B000; border-top: none; } + +#lbImageContainer, #lbIframeContainer { padding: 10px; } +#lbLoading { + position: absolute; top: 45%; left: 0%; height: 32px; width: 100%; text-align: center; line-height: 0; background: url(images/loading.gif) center no-repeat; +} + +#lbHoverNav { position: absolute; top: 0; left: 0; height: 100%; width: 100%; z-index: 10; } +#lbImageContainer>#lbHoverNav { left: 0; } +#lbHoverNav a { outline: none; } + +#lbPrev { width: 49%; height: 100%; background: transparent url(images/blank.gif) no-repeat; display: block; left: 0; float: left; } + #lbPrev.grey:hover, #lbPrev.grey:visited:hover { background: url(images/prev_grey.gif) left 15% no-repeat; } + #lbPrev.red:hover, #lbPrev.red:visited:hover { background: url(images/prev_red.gif) left 15% no-repeat; } + #lbPrev.green:hover, #lbPrev.green:visited:hover { background: url(images/prev_green.gif) left 15% no-repeat; } + #lbPrev.blue:hover, #lbPrev.blue:visited:hover { background: url(images/prev_blue.gif) left 15% no-repeat; } + #lbPrev.gold:hover, #lbPrev.gold:visited:hover { background: url(images/prev_gold.gif) left 15% no-repeat; } + +#lbNext { width: 49%; height: 100%; background: transparent url(images/blank.gif) no-repeat; display: block; right: 0; float: right; } + #lbNext.grey:hover, #lbNext.grey:visited:hover { background: url(images/next_grey.gif) right 15% no-repeat; } + #lbNext.red:hover, #lbNext.red:visited:hover { background: url(images/next_red.gif) right 15% no-repeat; } + #lbNext.green:hover, #lbNext.green:visited:hover { background: url(images/next_green.gif) right 15% no-repeat; } + #lbNext.blue:hover, #lbNext.blue:visited:hover { background: url(images/next_blue.gif) right 15% no-repeat; } + #lbNext.gold:hover, #lbNext.gold:visited:hover { background: url(images/next_gold.gif) right 15% no-repeat; } + +#lbPrev2, #lbNext2 { text-decoration: none; font-weight: bold; } + #lbPrev2.grey, #lbNext2.grey, #lbSpacer.grey { color: #333333; } + #lbPrev2.red, #lbNext2.red, #lbSpacer.red { color: #620000; } + #lbPrev2.green, #lbNext2.green, #lbSpacer.green { color: #003300; } + #lbPrev2.blue, #lbNext2.blue, #lbSpacer.blue { color: #01379E; } + #lbPrev2.gold, #lbNext2.gold, #lbSpacer.gold { color: #666600; } + +#lbPrev2_Off, #lbNext2_Off { font-weight: bold; } + #lbPrev2_Off.grey, #lbNext2_Off.grey { color: #CCCCCC; } + #lbPrev2_Off.red, #lbNext2_Off.red { color: #FFCCCC; } + #lbPrev2_Off.green, #lbNext2_Off.green { color: #82FF82; } + #lbPrev2_Off.blue, #lbNext2_Off.blue { color: #B7CAEE; } + #lbPrev2_Off.gold, #lbNext2_Off.gold { color: #E1E100; } + +#lbDetailsData { padding: 0 10px; } + #lbDetailsData.grey { color: #333333; } + #lbDetailsData.red { color: #620000; } + #lbDetailsData.green { color: #003300; } + #lbDetailsData.blue { color: #01379E; } + #lbDetailsData.gold { color: #666600; } + +#lbDetails { width: 60%; float: left; text-align: left; } +#lbCaption { display: block; font-weight: bold; } +#lbNumberDisplay { float: left; display: block; padding-bottom: 1.0em; } +#lbNavDisplay { float: left; display: block; padding-bottom: 1.0em; } + +#lbClose { width: 64px; height: 28px; float: right; margin-bottom: 1px; } + #lbClose.grey { background: url(images/close_grey.png) no-repeat; } + #lbClose.red { background: url(images/close_red.png) no-repeat; } + #lbClose.green { background: url(images/close_green.png) no-repeat; } + #lbClose.blue { background: url(images/close_blue.png) no-repeat; } + #lbClose.gold { background: url(images/close_gold.png) no-repeat; } + +#lbPlay { width: 64px; height: 28px; float: right; margin-bottom: 1px; } + #lbPlay.grey { background: url(images/play_grey.png) no-repeat; } + #lbPlay.red { background: url(images/play_red.png) no-repeat; } + #lbPlay.green { background: url(images/play_green.png) no-repeat; } + #lbPlay.blue { background: url(images/play_blue.png) no-repeat; } + #lbPlay.gold { background: url(images/play_gold.png) no-repeat; } + +#lbPause { width: 64px; height: 28px; float: right; margin-bottom: 1px; } + #lbPause.grey { background: url(images/pause_grey.png) no-repeat; } + #lbPause.red { background: url(images/pause_red.png) no-repeat; } + #lbPause.green { background: url(images/pause_green.png) no-repeat; } + #lbPause.blue { background: url(images/pause_blue.png) no-repeat; } + #lbPause.gold { background: url(images/pause_gold.png) no-repeat; } \ No newline at end of file diff --git a/plugins/tidypics/vendors/lytebox/lytebox.js b/plugins/tidypics/vendors/lytebox/lytebox.js new file mode 100644 index 0000000000000000000000000000000000000000..1cf7210d0ab4560c0a828107debaa80552c510ba --- /dev/null +++ b/plugins/tidypics/vendors/lytebox/lytebox.js @@ -0,0 +1,843 @@ +//***********************************************************************************************************************************/ +// LyteBox v3.22 +// +// Author: Markus F. Hay +// Website: http://www.dolem.com/lytebox +// Date: October 2, 2007 +// License: Creative Commons Attribution 3.0 License (http://creativecommons.org/licenses/by/3.0/) +// Browsers: Tested successfully on WinXP with the following browsers (using no DOCTYPE and Strict/Transitional/Loose DOCTYPES): +// * Firefox: 2.0.0.7, 1.5.0.12 +// * Internet Explorer: 7.0, 6.0 SP2, 5.5 SP2 +// * Opera: 9.23 +// +// Releases: For up-to-date and complete release information, visit http://www.dolem.com/forum/showthread.php?tid=62 +// * v3.22 (10/02/07) +// * v3.21 (09/30/07) +// * v3.20 (07/12/07) +// * v3.10 (05/28/07) +// * v3.00 (05/15/07) +// * v2.02 (11/13/06) +// +// Credit: LyteBox was originally derived from the Lightbox class (v2.02) that was written by Lokesh Dhakar. For more +// information please visit http://huddletogether.com/projects/lightbox2/ +//***********************************************************************************************************************************/ +Array.prototype.removeDuplicates = function () { for (var i = 1; i < this.length; i++) { if (this[i][0] == this[i-1][0]) { this.splice(i,1); } } } +Array.prototype.empty = function () { for (var i = 0; i <= this.length; i++) { this.shift(); } } +String.prototype.trim = function () { return this.replace(/^\s+|\s+$/g, ''); } + +function LyteBox() { + /*** Start Global Configuration ***/ + this.theme = 'grey'; // themes: grey (default), red, green, blue, gold + this.hideFlash = true; // controls whether or not Flash objects should be hidden + this.outerBorder = true; // controls whether to show the outer grey (or theme) border + this.resizeSpeed = 8; // controls the speed of the image resizing (1=slowest and 10=fastest) + this.maxOpacity = 80; // higher opacity = darker overlay, lower opacity = lighter overlay + this.navType = 1; // 1 = "Prev/Next" buttons on top left and left (default), 2 = "<< prev | next >>" links next to image number + this.autoResize = true; // controls whether or not images should be resized if larger than the browser window dimensions + this.doAnimations = true; // controls whether or not "animate" Lytebox, i.e. resize transition between images, fade in/out effects, etc. + + this.borderSize = 12; // if you adjust the padding in the CSS, you will need to update this variable -- otherwise, leave this alone... + /*** End Global Configuration ***/ + + /*** Configure Slideshow Options ***/ + this.slideInterval = 4000; // Change value (milliseconds) to increase/decrease the time between "slides" (10000 = 10 seconds) + this.showNavigation = true; // true to display Next/Prev buttons/text during slideshow, false to hide + this.showClose = true; // true to display the Close button, false to hide + this.showDetails = true; // true to display image details (caption, count), false to hide + this.showPlayPause = true; // true to display pause/play buttons next to close button, false to hide + this.autoEnd = true; // true to automatically close Lytebox after the last image is reached, false to keep open + this.pauseOnNextClick = false; // true to pause the slideshow when the "Next" button is clicked + this.pauseOnPrevClick = true; // true to pause the slideshow when the "Prev" button is clicked + /*** End Slideshow Configuration ***/ + + if(this.resizeSpeed > 10) { this.resizeSpeed = 10; } + if(this.resizeSpeed < 1) { resizeSpeed = 1; } + this.resizeDuration = (11 - this.resizeSpeed) * 0.15; + this.resizeWTimerArray = new Array(); + this.resizeWTimerCount = 0; + this.resizeHTimerArray = new Array(); + this.resizeHTimerCount = 0; + this.showContentTimerArray = new Array(); + this.showContentTimerCount = 0; + this.overlayTimerArray = new Array(); + this.overlayTimerCount = 0; + this.imageTimerArray = new Array(); + this.imageTimerCount = 0; + this.timerIDArray = new Array(); + this.timerIDCount = 0; + this.slideshowIDArray = new Array(); + this.slideshowIDCount = 0; + this.imageArray = new Array(); + this.activeImage = null; + this.slideArray = new Array(); + this.activeSlide = null; + this.frameArray = new Array(); + this.activeFrame = null; + this.checkFrame(); + this.isSlideshow = false; + this.isLyteframe = false; + /*@cc_on + /*@if (@_jscript) + this.ie = (document.all && !window.opera) ? true : false; + /*@else @*/ + this.ie = false; + /*@end + @*/ + this.ie7 = (this.ie && window.XMLHttpRequest); + this.initialize(); +} +LyteBox.prototype.initialize = function() { + this.updateLyteboxItems(); + var objBody = this.doc.getElementsByTagName("body").item(0); + if (this.doc.getElementById('lbOverlay')) { + objBody.removeChild(this.doc.getElementById("lbOverlay")); + objBody.removeChild(this.doc.getElementById("lbMain")); + } + var objOverlay = this.doc.createElement("div"); + objOverlay.setAttribute('id','lbOverlay'); + objOverlay.setAttribute((this.ie ? 'className' : 'class'), this.theme); + if ((this.ie && !this.ie7) || (this.ie7 && this.doc.compatMode == 'BackCompat')) { + objOverlay.style.position = 'absolute'; + } + objOverlay.style.display = 'none'; + objBody.appendChild(objOverlay); + var objLytebox = this.doc.createElement("div"); + objLytebox.setAttribute('id','lbMain'); + objLytebox.style.display = 'none'; + objBody.appendChild(objLytebox); + var objOuterContainer = this.doc.createElement("div"); + objOuterContainer.setAttribute('id','lbOuterContainer'); + objOuterContainer.setAttribute((this.ie ? 'className' : 'class'), this.theme); + objLytebox.appendChild(objOuterContainer); + var objIframeContainer = this.doc.createElement("div"); + objIframeContainer.setAttribute('id','lbIframeContainer'); + objIframeContainer.style.display = 'none'; + objOuterContainer.appendChild(objIframeContainer); + var objIframe = this.doc.createElement("iframe"); + objIframe.setAttribute('id','lbIframe'); + objIframe.setAttribute('name','lbIframe'); + objIframe.style.display = 'none'; + objIframeContainer.appendChild(objIframe); + var objImageContainer = this.doc.createElement("div"); + objImageContainer.setAttribute('id','lbImageContainer'); + objOuterContainer.appendChild(objImageContainer); + var objLyteboxImage = this.doc.createElement("img"); + objLyteboxImage.setAttribute('id','lbImage'); + objImageContainer.appendChild(objLyteboxImage); + var objLoading = this.doc.createElement("div"); + objLoading.setAttribute('id','lbLoading'); + objOuterContainer.appendChild(objLoading); + var objDetailsContainer = this.doc.createElement("div"); + objDetailsContainer.setAttribute('id','lbDetailsContainer'); + objDetailsContainer.setAttribute((this.ie ? 'className' : 'class'), this.theme); + objLytebox.appendChild(objDetailsContainer); + var objDetailsData =this.doc.createElement("div"); + objDetailsData.setAttribute('id','lbDetailsData'); + objDetailsData.setAttribute((this.ie ? 'className' : 'class'), this.theme); + objDetailsContainer.appendChild(objDetailsData); + var objDetails = this.doc.createElement("div"); + objDetails.setAttribute('id','lbDetails'); + objDetailsData.appendChild(objDetails); + var objCaption = this.doc.createElement("span"); + objCaption.setAttribute('id','lbCaption'); + objDetails.appendChild(objCaption); + var objHoverNav = this.doc.createElement("div"); + objHoverNav.setAttribute('id','lbHoverNav'); + objImageContainer.appendChild(objHoverNav); + var objBottomNav = this.doc.createElement("div"); + objBottomNav.setAttribute('id','lbBottomNav'); + objDetailsData.appendChild(objBottomNav); + var objPrev = this.doc.createElement("a"); + objPrev.setAttribute('id','lbPrev'); + objPrev.setAttribute((this.ie ? 'className' : 'class'), this.theme); + objPrev.setAttribute('href','#'); + objHoverNav.appendChild(objPrev); + var objNext = this.doc.createElement("a"); + objNext.setAttribute('id','lbNext'); + objNext.setAttribute((this.ie ? 'className' : 'class'), this.theme); + objNext.setAttribute('href','#'); + objHoverNav.appendChild(objNext); + var objNumberDisplay = this.doc.createElement("span"); + objNumberDisplay.setAttribute('id','lbNumberDisplay'); + objDetails.appendChild(objNumberDisplay); + var objNavDisplay = this.doc.createElement("span"); + objNavDisplay.setAttribute('id','lbNavDisplay'); + objNavDisplay.style.display = 'none'; + objDetails.appendChild(objNavDisplay); + var objClose = this.doc.createElement("a"); + objClose.setAttribute('id','lbClose'); + objClose.setAttribute((this.ie ? 'className' : 'class'), this.theme); + objClose.setAttribute('href','#'); + objBottomNav.appendChild(objClose); + var objPause = this.doc.createElement("a"); + objPause.setAttribute('id','lbPause'); + objPause.setAttribute((this.ie ? 'className' : 'class'), this.theme); + objPause.setAttribute('href','#'); + objPause.style.display = 'none'; + objBottomNav.appendChild(objPause); + var objPlay = this.doc.createElement("a"); + objPlay.setAttribute('id','lbPlay'); + objPlay.setAttribute((this.ie ? 'className' : 'class'), this.theme); + objPlay.setAttribute('href','#'); + objPlay.style.display = 'none'; + objBottomNav.appendChild(objPlay); +}; +LyteBox.prototype.updateLyteboxItems = function() { + var anchors = (this.isFrame) ? window.parent.frames[window.name].document.getElementsByTagName('a') : document.getElementsByTagName('a'); + for (var i = 0; i < anchors.length; i++) { + var anchor = anchors[i]; + var relAttribute = String(anchor.getAttribute('rel')); + if (anchor.getAttribute('href')) { + if (relAttribute.toLowerCase().match('lytebox')) { + anchor.onclick = function () { myLytebox.start(this, false, false); return false; } + } else if (relAttribute.toLowerCase().match('lyteshow')) { + anchor.onclick = function () { myLytebox.start(this, true, false); return false; } + } else if (relAttribute.toLowerCase().match('lyteframe')) { + anchor.onclick = function () { myLytebox.start(this, false, true); return false; } + } + } + } +}; +LyteBox.prototype.start = function(imageLink, doSlide, doFrame) { + if (this.ie && !this.ie7) { this.toggleSelects('hide'); } + if (this.hideFlash) { this.toggleFlash('hide'); } + this.isLyteframe = (doFrame ? true : false); + var pageSize = this.getPageSize(); + var objOverlay = this.doc.getElementById('lbOverlay'); + var objBody = this.doc.getElementsByTagName("body").item(0); + objOverlay.style.height = pageSize[1] + "px"; + objOverlay.style.display = ''; + this.appear('lbOverlay', (this.doAnimations ? 0 : this.maxOpacity)); + var anchors = (this.isFrame) ? window.parent.frames[window.name].document.getElementsByTagName('a') : document.getElementsByTagName('a'); + if (this.isLyteframe) { + this.frameArray = []; + this.frameNum = 0; + if ((imageLink.getAttribute('rel') == 'lyteframe')) { + var rev = imageLink.getAttribute('rev'); + this.frameArray.push(new Array(imageLink.getAttribute('href'), imageLink.getAttribute('title'), (rev == null || rev == '' ? 'width: 400px; height: 400px; scrolling: auto;' : rev))); + } else { + if (imageLink.getAttribute('rel').indexOf('lyteframe') != -1) { + for (var i = 0; i < anchors.length; i++) { + var anchor = anchors[i]; + if (anchor.getAttribute('href') && (anchor.getAttribute('rel') == imageLink.getAttribute('rel'))) { + var rev = anchor.getAttribute('rev'); + this.frameArray.push(new Array(anchor.getAttribute('href'), anchor.getAttribute('title'), (rev == null || rev == '' ? 'width: 400px; height: 400px; scrolling: auto;' : rev))); + } + } + this.frameArray.removeDuplicates(); + while(this.frameArray[this.frameNum][0] != imageLink.getAttribute('href')) { this.frameNum++; } + } + } + } else { + this.imageArray = []; + this.imageNum = 0; + this.slideArray = []; + this.slideNum = 0; + if ((imageLink.getAttribute('rel') == 'lytebox')) { + this.imageArray.push(new Array(imageLink.getAttribute('href'), imageLink.getAttribute('title'))); + } else { + if (imageLink.getAttribute('rel').indexOf('lytebox') != -1) { + for (var i = 0; i < anchors.length; i++) { + var anchor = anchors[i]; + if (anchor.getAttribute('href') && (anchor.getAttribute('rel') == imageLink.getAttribute('rel'))) { + this.imageArray.push(new Array(anchor.getAttribute('href'), anchor.getAttribute('title'))); + } + } + this.imageArray.removeDuplicates(); + while(this.imageArray[this.imageNum][0] != imageLink.getAttribute('href')) { this.imageNum++; } + } + if (imageLink.getAttribute('rel').indexOf('lyteshow') != -1) { + for (var i = 0; i < anchors.length; i++) { + var anchor = anchors[i]; + if (anchor.getAttribute('href') && (anchor.getAttribute('rel') == imageLink.getAttribute('rel'))) { + this.slideArray.push(new Array(anchor.getAttribute('href'), anchor.getAttribute('title'))); + } + } + this.slideArray.removeDuplicates(); + while(this.slideArray[this.slideNum][0] != imageLink.getAttribute('href')) { this.slideNum++; } + } + } + } + var object = this.doc.getElementById('lbMain'); + object.style.top = (this.getPageScroll() + (pageSize[3] / 15)) + "px"; + object.style.display = ''; + if (!this.outerBorder) { + this.doc.getElementById('lbOuterContainer').style.border = 'none'; + this.doc.getElementById('lbDetailsContainer').style.border = 'none'; + } else { + this.doc.getElementById('lbOuterContainer').style.borderBottom = ''; + this.doc.getElementById('lbOuterContainer').setAttribute((this.ie ? 'className' : 'class'), this.theme); + } + this.doc.getElementById('lbOverlay').onclick = function() { myLytebox.end(); return false; } + this.doc.getElementById('lbMain').onclick = function(e) { + var e = e; + if (!e) { + if (window.parent.frames[window.name] && (parent.document.getElementsByTagName('frameset').length <= 0)) { + e = window.parent.window.event; + } else { + e = window.event; + } + } + var id = (e.target ? e.target.id : e.srcElement.id); + if (id == 'lbMain') { myLytebox.end(); return false; } + } + this.doc.getElementById('lbClose').onclick = function() { myLytebox.end(); return false; } + this.doc.getElementById('lbPause').onclick = function() { myLytebox.togglePlayPause("lbPause", "lbPlay"); return false; } + this.doc.getElementById('lbPlay').onclick = function() { myLytebox.togglePlayPause("lbPlay", "lbPause"); return false; } + this.isSlideshow = doSlide; + this.isPaused = (this.slideNum != 0 ? true : false); + if (this.isSlideshow && this.showPlayPause && this.isPaused) { + this.doc.getElementById('lbPlay').style.display = ''; + this.doc.getElementById('lbPause').style.display = 'none'; + } + if (this.isLyteframe) { + this.changeContent(this.frameNum); + } else { + if (this.isSlideshow) { + this.changeContent(this.slideNum); + } else { + this.changeContent(this.imageNum); + } + } +}; +LyteBox.prototype.changeContent = function(imageNum) { + if (this.isSlideshow) { + for (var i = 0; i < this.slideshowIDCount; i++) { window.clearTimeout(this.slideshowIDArray[i]); } + } + this.activeImage = this.activeSlide = this.activeFrame = imageNum; + if (!this.outerBorder) { + this.doc.getElementById('lbOuterContainer').style.border = 'none'; + this.doc.getElementById('lbDetailsContainer').style.border = 'none'; + } else { + this.doc.getElementById('lbOuterContainer').style.borderBottom = ''; + this.doc.getElementById('lbOuterContainer').setAttribute((this.ie ? 'className' : 'class'), this.theme); + } + this.doc.getElementById('lbLoading').style.display = ''; + this.doc.getElementById('lbImage').style.display = 'none'; + this.doc.getElementById('lbIframe').style.display = 'none'; + this.doc.getElementById('lbPrev').style.display = 'none'; + this.doc.getElementById('lbNext').style.display = 'none'; + this.doc.getElementById('lbIframeContainer').style.display = 'none'; + this.doc.getElementById('lbDetailsContainer').style.display = 'none'; + this.doc.getElementById('lbNumberDisplay').style.display = 'none'; + if (this.navType == 2 || this.isLyteframe) { + object = this.doc.getElementById('lbNavDisplay'); + object.innerHTML = ' <span id="lbPrev2_Off" style="display: none;" class="' + this.theme + '">« prev</span><a href="#" id="lbPrev2" class="' + this.theme + '" style="display: none;">« prev</a> <b id="lbSpacer" class="' + this.theme + '">||</b> <span id="lbNext2_Off" style="display: none;" class="' + this.theme + '">next »</span><a href="#" id="lbNext2" class="' + this.theme + '" style="display: none;">next »</a>'; + object.style.display = 'none'; + } + if (this.isLyteframe) { + var iframe = myLytebox.doc.getElementById('lbIframe'); + var styles = this.frameArray[this.activeFrame][2]; + var aStyles = styles.split(';'); + for (var i = 0; i < aStyles.length; i++) { + if (aStyles[i].indexOf('width:') >= 0) { + var w = aStyles[i].replace('width:', ''); + iframe.width = w.trim(); + } else if (aStyles[i].indexOf('height:') >= 0) { + var h = aStyles[i].replace('height:', ''); + iframe.height = h.trim(); + } else if (aStyles[i].indexOf('scrolling:') >= 0) { + var s = aStyles[i].replace('scrolling:', ''); + iframe.scrolling = s.trim(); + } else if (aStyles[i].indexOf('border:') >= 0) { + // Not implemented yet, as there are cross-platform issues with setting the border (from a GUI standpoint) + //var b = aStyles[i].replace('border:', ''); + //iframe.style.border = b.trim(); + } + } + this.resizeContainer(parseInt(iframe.width), parseInt(iframe.height)); + } else { + imgPreloader = new Image(); + imgPreloader.onload = function() { + var imageWidth = imgPreloader.width; + var imageHeight = imgPreloader.height; + if (myLytebox.autoResize) { + var pagesize = myLytebox.getPageSize(); + var x = pagesize[2] - 150; + var y = pagesize[3] - 150; + if (imageWidth > x) { + imageHeight = Math.round(imageHeight * (x / imageWidth)); + imageWidth = x; + if (imageHeight > y) { + imageWidth = Math.round(imageWidth * (y / imageHeight)); + imageHeight = y; + } + } else if (imageHeight > y) { + imageWidth = Math.round(imageWidth * (y / imageHeight)); + imageHeight = y; + if (imageWidth > x) { + imageHeight = Math.round(imageHeight * (x / imageWidth)); + imageWidth = x; + } + } + } + var lbImage = myLytebox.doc.getElementById('lbImage') + lbImage.src = (myLytebox.isSlideshow ? myLytebox.slideArray[myLytebox.activeSlide][0] : myLytebox.imageArray[myLytebox.activeImage][0]); + lbImage.width = imageWidth; + lbImage.height = imageHeight; + myLytebox.resizeContainer(imageWidth, imageHeight); + imgPreloader.onload = function() {}; + } + imgPreloader.src = (this.isSlideshow ? this.slideArray[this.activeSlide][0] : this.imageArray[this.activeImage][0]); + } +}; +LyteBox.prototype.resizeContainer = function(imgWidth, imgHeight) { + this.wCur = this.doc.getElementById('lbOuterContainer').offsetWidth; + this.hCur = this.doc.getElementById('lbOuterContainer').offsetHeight; + this.xScale = ((imgWidth + (this.borderSize * 2)) / this.wCur) * 100; + this.yScale = ((imgHeight + (this.borderSize * 2)) / this.hCur) * 100; + var wDiff = (this.wCur - this.borderSize * 2) - imgWidth; + var hDiff = (this.hCur - this.borderSize * 2) - imgHeight; + if (!(hDiff == 0)) { + this.hDone = false; + this.resizeH('lbOuterContainer', this.hCur, imgHeight + this.borderSize*2, this.getPixelRate(this.hCur, imgHeight)); + } else { + this.hDone = true; + } + if (!(wDiff == 0)) { + this.wDone = false; + this.resizeW('lbOuterContainer', this.wCur, imgWidth + this.borderSize*2, this.getPixelRate(this.wCur, imgWidth)); + } else { + this.wDone = true; + } + if ((hDiff == 0) && (wDiff == 0)) { + if (this.ie){ this.pause(250); } else { this.pause(100); } + } + this.doc.getElementById('lbPrev').style.height = imgHeight + "px"; + this.doc.getElementById('lbNext').style.height = imgHeight + "px"; + this.doc.getElementById('lbDetailsContainer').style.width = (imgWidth + (this.borderSize * 2) + (this.ie && this.doc.compatMode == "BackCompat" && this.outerBorder ? 2 : 0)) + "px"; + this.showContent(); +}; +LyteBox.prototype.showContent = function() { + if (this.wDone && this.hDone) { + for (var i = 0; i < this.showContentTimerCount; i++) { window.clearTimeout(this.showContentTimerArray[i]); } + if (this.outerBorder) { + this.doc.getElementById('lbOuterContainer').style.borderBottom = 'none'; + } + this.doc.getElementById('lbLoading').style.display = 'none'; + if (this.isLyteframe) { + this.doc.getElementById('lbIframe').style.display = ''; + this.appear('lbIframe', (this.doAnimations ? 0 : 100)); + } else { + this.doc.getElementById('lbImage').style.display = ''; + this.appear('lbImage', (this.doAnimations ? 0 : 100)); + this.preloadNeighborImages(); + } + if (this.isSlideshow) { + if(this.activeSlide == (this.slideArray.length - 1)) { + if (this.autoEnd) { + this.slideshowIDArray[this.slideshowIDCount++] = setTimeout("myLytebox.end('slideshow')", this.slideInterval); + } + } else { + if (!this.isPaused) { + this.slideshowIDArray[this.slideshowIDCount++] = setTimeout("myLytebox.changeContent("+(this.activeSlide+1)+")", this.slideInterval); + } + } + this.doc.getElementById('lbHoverNav').style.display = (this.showNavigation && this.navType == 1 ? '' : 'none'); + this.doc.getElementById('lbClose').style.display = (this.showClose ? '' : 'none'); + this.doc.getElementById('lbDetails').style.display = (this.showDetails ? '' : 'none'); + this.doc.getElementById('lbPause').style.display = (this.showPlayPause && !this.isPaused ? '' : 'none'); + this.doc.getElementById('lbPlay').style.display = (this.showPlayPause && !this.isPaused ? 'none' : ''); + this.doc.getElementById('lbNavDisplay').style.display = (this.showNavigation && this.navType == 2 ? '' : 'none'); + } else { + this.doc.getElementById('lbHoverNav').style.display = (this.navType == 1 && !this.isLyteframe ? '' : 'none'); + if ((this.navType == 2 && !this.isLyteframe && this.imageArray.length > 1) || (this.frameArray.length > 1 && this.isLyteframe)) { + this.doc.getElementById('lbNavDisplay').style.display = ''; + } else { + this.doc.getElementById('lbNavDisplay').style.display = 'none'; + } + this.doc.getElementById('lbClose').style.display = ''; + this.doc.getElementById('lbDetails').style.display = ''; + this.doc.getElementById('lbPause').style.display = 'none'; + this.doc.getElementById('lbPlay').style.display = 'none'; + } + this.doc.getElementById('lbImageContainer').style.display = (this.isLyteframe ? 'none' : ''); + this.doc.getElementById('lbIframeContainer').style.display = (this.isLyteframe ? '' : 'none'); + try { + this.doc.getElementById('lbIframe').src = this.frameArray[this.activeFrame][0]; + } catch(e) { } + } else { + this.showContentTimerArray[this.showContentTimerCount++] = setTimeout("myLytebox.showContent()", 200); + } +}; +LyteBox.prototype.updateDetails = function() { + var object = this.doc.getElementById('lbCaption'); + var sTitle = (this.isSlideshow ? this.slideArray[this.activeSlide][1] : (this.isLyteframe ? this.frameArray[this.activeFrame][1] : this.imageArray[this.activeImage][1])); + object.style.display = ''; + object.innerHTML = (sTitle == null ? '' : sTitle); + this.updateNav(); + this.doc.getElementById('lbDetailsContainer').style.display = ''; + object = this.doc.getElementById('lbNumberDisplay'); + if (this.isSlideshow && this.slideArray.length > 1) { + object.style.display = ''; + object.innerHTML = "Image " + eval(this.activeSlide + 1) + " of " + this.slideArray.length; + this.doc.getElementById('lbNavDisplay').style.display = (this.navType == 2 && this.showNavigation ? '' : 'none'); + } else if (this.imageArray.length > 1 && !this.isLyteframe) { + object.style.display = ''; + object.innerHTML = "Image " + eval(this.activeImage + 1) + " of " + this.imageArray.length; + this.doc.getElementById('lbNavDisplay').style.display = (this.navType == 2 ? '' : 'none'); + } else if (this.frameArray.length > 1 && this.isLyteframe) { + object.style.display = ''; + object.innerHTML = "Page " + eval(this.activeFrame + 1) + " of " + this.frameArray.length; + this.doc.getElementById('lbNavDisplay').style.display = ''; + } else { + this.doc.getElementById('lbNavDisplay').style.display = 'none'; + } + this.appear('lbDetailsContainer', (this.doAnimations ? 0 : 100)); +}; +LyteBox.prototype.updateNav = function() { + if (this.isSlideshow) { + if (this.activeSlide != 0) { + var object = (this.navType == 2 ? this.doc.getElementById('lbPrev2') : this.doc.getElementById('lbPrev')); + object.style.display = ''; + object.onclick = function() { + if (myLytebox.pauseOnPrevClick) { myLytebox.togglePlayPause("lbPause", "lbPlay"); } + myLytebox.changeContent(myLytebox.activeSlide - 1); return false; + } + } else { + if (this.navType == 2) { this.doc.getElementById('lbPrev2_Off').style.display = ''; } + } + if (this.activeSlide != (this.slideArray.length - 1)) { + var object = (this.navType == 2 ? this.doc.getElementById('lbNext2') : this.doc.getElementById('lbNext')); + object.style.display = ''; + object.onclick = function() { + if (myLytebox.pauseOnNextClick) { myLytebox.togglePlayPause("lbPause", "lbPlay"); } + myLytebox.changeContent(myLytebox.activeSlide + 1); return false; + } + } else { + if (this.navType == 2) { this.doc.getElementById('lbNext2_Off').style.display = ''; } + } + } else if (this.isLyteframe) { + if(this.activeFrame != 0) { + var object = this.doc.getElementById('lbPrev2'); + object.style.display = ''; + object.onclick = function() { + myLytebox.changeContent(myLytebox.activeFrame - 1); return false; + } + } else { + this.doc.getElementById('lbPrev2_Off').style.display = ''; + } + if(this.activeFrame != (this.frameArray.length - 1)) { + var object = this.doc.getElementById('lbNext2'); + object.style.display = ''; + object.onclick = function() { + myLytebox.changeContent(myLytebox.activeFrame + 1); return false; + } + } else { + this.doc.getElementById('lbNext2_Off').style.display = ''; + } + } else { + if(this.activeImage != 0) { + var object = (this.navType == 2 ? this.doc.getElementById('lbPrev2') : this.doc.getElementById('lbPrev')); + object.style.display = ''; + object.onclick = function() { + myLytebox.changeContent(myLytebox.activeImage - 1); return false; + } + } else { + if (this.navType == 2) { this.doc.getElementById('lbPrev2_Off').style.display = ''; } + } + if(this.activeImage != (this.imageArray.length - 1)) { + var object = (this.navType == 2 ? this.doc.getElementById('lbNext2') : this.doc.getElementById('lbNext')); + object.style.display = ''; + object.onclick = function() { + myLytebox.changeContent(myLytebox.activeImage + 1); return false; + } + } else { + if (this.navType == 2) { this.doc.getElementById('lbNext2_Off').style.display = ''; } + } + } + this.enableKeyboardNav(); +}; +LyteBox.prototype.enableKeyboardNav = function() { document.onkeydown = this.keyboardAction; }; +LyteBox.prototype.disableKeyboardNav = function() { document.onkeydown = ''; }; +LyteBox.prototype.keyboardAction = function(e) { + var keycode = key = escape = null; + keycode = (e == null) ? event.keyCode : e.which; + key = String.fromCharCode(keycode).toLowerCase(); + escape = (e == null) ? 27 : e.DOM_VK_ESCAPE; + if ((key == 'x') || (key == 'c') || (keycode == escape)) { + myLytebox.end(); + } else if ((key == 'p') || (keycode == 37)) { + if (myLytebox.isSlideshow) { + if(myLytebox.activeSlide != 0) { + myLytebox.disableKeyboardNav(); + myLytebox.changeContent(myLytebox.activeSlide - 1); + } + } else if (myLytebox.isLyteframe) { + if(myLytebox.activeFrame != 0) { + myLytebox.disableKeyboardNav(); + myLytebox.changeContent(myLytebox.activeFrame - 1); + } + } else { + if(myLytebox.activeImage != 0) { + myLytebox.disableKeyboardNav(); + myLytebox.changeContent(myLytebox.activeImage - 1); + } + } + } else if ((key == 'n') || (keycode == 39)) { + if (myLytebox.isSlideshow) { + if(myLytebox.activeSlide != (myLytebox.slideArray.length - 1)) { + myLytebox.disableKeyboardNav(); + myLytebox.changeContent(myLytebox.activeSlide + 1); + } + } else if (myLytebox.isLyteframe) { + if(myLytebox.activeFrame != (myLytebox.frameArray.length - 1)) { + myLytebox.disableKeyboardNav(); + myLytebox.changeContent(myLytebox.activeFrame + 1); + } + } else { + if(myLytebox.activeImage != (myLytebox.imageArray.length - 1)) { + myLytebox.disableKeyboardNav(); + myLytebox.changeContent(myLytebox.activeImage + 1); + } + } + } +}; +LyteBox.prototype.preloadNeighborImages = function() { + if (this.isSlideshow) { + if ((this.slideArray.length - 1) > this.activeSlide) { + preloadNextImage = new Image(); + preloadNextImage.src = this.slideArray[this.activeSlide + 1][0]; + } + if(this.activeSlide > 0) { + preloadPrevImage = new Image(); + preloadPrevImage.src = this.slideArray[this.activeSlide - 1][0]; + } + } else { + if ((this.imageArray.length - 1) > this.activeImage) { + preloadNextImage = new Image(); + preloadNextImage.src = this.imageArray[this.activeImage + 1][0]; + } + if(this.activeImage > 0) { + preloadPrevImage = new Image(); + preloadPrevImage.src = this.imageArray[this.activeImage - 1][0]; + } + } +}; +LyteBox.prototype.togglePlayPause = function(hideID, showID) { + if (this.isSlideshow && hideID == "lbPause") { + for (var i = 0; i < this.slideshowIDCount; i++) { window.clearTimeout(this.slideshowIDArray[i]); } + } + this.doc.getElementById(hideID).style.display = 'none'; + this.doc.getElementById(showID).style.display = ''; + if (hideID == "lbPlay") { + this.isPaused = false; + if (this.activeSlide == (this.slideArray.length - 1)) { + this.end(); + } else { + this.changeContent(this.activeSlide + 1); + } + } else { + this.isPaused = true; + } +}; +LyteBox.prototype.end = function(caller) { + var closeClick = (caller == 'slideshow' ? false : true); + if (this.isSlideshow && this.isPaused && !closeClick) { return; } + this.disableKeyboardNav(); + this.doc.getElementById('lbMain').style.display = 'none'; + this.fade('lbOverlay', (this.doAnimations ? this.maxOpacity : 0)); + this.toggleSelects('visible'); + if (this.hideFlash) { this.toggleFlash('visible'); } + if (this.isSlideshow) { + for (var i = 0; i < this.slideshowIDCount; i++) { window.clearTimeout(this.slideshowIDArray[i]); } + } + if (this.isLyteframe) { + this.initialize(); + } +}; +LyteBox.prototype.checkFrame = function() { + if (window.parent.frames[window.name] && (parent.document.getElementsByTagName('frameset').length <= 0)) { + this.isFrame = true; + this.lytebox = "window.parent." + window.name + ".myLytebox"; + this.doc = parent.document; + } else { + this.isFrame = false; + this.lytebox = "myLytebox"; + this.doc = document; + } +}; +LyteBox.prototype.getPixelRate = function(cur, img) { + var diff = (img > cur) ? img - cur : cur - img; + if (diff >= 0 && diff <= 100) { return 10; } + if (diff > 100 && diff <= 200) { return 15; } + if (diff > 200 && diff <= 300) { return 20; } + if (diff > 300 && diff <= 400) { return 25; } + if (diff > 400 && diff <= 500) { return 30; } + if (diff > 500 && diff <= 600) { return 35; } + if (diff > 600 && diff <= 700) { return 40; } + if (diff > 700) { return 45; } +}; +LyteBox.prototype.appear = function(id, opacity) { + var object = this.doc.getElementById(id).style; + object.opacity = (opacity / 100); + object.MozOpacity = (opacity / 100); + object.KhtmlOpacity = (opacity / 100); + object.filter = "alpha(opacity=" + (opacity + 10) + ")"; + if (opacity == 100 && (id == 'lbImage' || id == 'lbIframe')) { + try { object.removeAttribute("filter"); } catch(e) {} /* Fix added for IE Alpha Opacity Filter bug. */ + this.updateDetails(); + } else if (opacity >= this.maxOpacity && id == 'lbOverlay') { + for (var i = 0; i < this.overlayTimerCount; i++) { window.clearTimeout(this.overlayTimerArray[i]); } + return; + } else if (opacity >= 100 && id == 'lbDetailsContainer') { + try { object.removeAttribute("filter"); } catch(e) {} /* Fix added for IE Alpha Opacity Filter bug. */ + for (var i = 0; i < this.imageTimerCount; i++) { window.clearTimeout(this.imageTimerArray[i]); } + this.doc.getElementById('lbOverlay').style.height = this.getPageSize()[1] + "px"; + } else { + if (id == 'lbOverlay') { + this.overlayTimerArray[this.overlayTimerCount++] = setTimeout("myLytebox.appear('" + id + "', " + (opacity+20) + ")", 1); + } else { + this.imageTimerArray[this.imageTimerCount++] = setTimeout("myLytebox.appear('" + id + "', " + (opacity+10) + ")", 1); + } + } +}; +LyteBox.prototype.fade = function(id, opacity) { + var object = this.doc.getElementById(id).style; + object.opacity = (opacity / 100); + object.MozOpacity = (opacity / 100); + object.KhtmlOpacity = (opacity / 100); + object.filter = "alpha(opacity=" + opacity + ")"; + if (opacity <= 0) { + try { + object.display = 'none'; + } catch(err) { } + } else if (id == 'lbOverlay') { + this.overlayTimerArray[this.overlayTimerCount++] = setTimeout("myLytebox.fade('" + id + "', " + (opacity-20) + ")", 1); + } else { + this.timerIDArray[this.timerIDCount++] = setTimeout("myLytebox.fade('" + id + "', " + (opacity-10) + ")", 1); + } +}; +LyteBox.prototype.resizeW = function(id, curW, maxW, pixelrate, speed) { + if (!this.hDone) { + this.resizeWTimerArray[this.resizeWTimerCount++] = setTimeout("myLytebox.resizeW('" + id + "', " + curW + ", " + maxW + ", " + pixelrate + ")", 100); + return; + } + var object = this.doc.getElementById(id); + var timer = speed ? speed : (this.resizeDuration/2); + var newW = (this.doAnimations ? curW : maxW); + object.style.width = (newW) + "px"; + if (newW < maxW) { + newW += (newW + pixelrate >= maxW) ? (maxW - newW) : pixelrate; + } else if (newW > maxW) { + newW -= (newW - pixelrate <= maxW) ? (newW - maxW) : pixelrate; + } + this.resizeWTimerArray[this.resizeWTimerCount++] = setTimeout("myLytebox.resizeW('" + id + "', " + newW + ", " + maxW + ", " + pixelrate + ", " + (timer+0.02) + ")", timer+0.02); + if (parseInt(object.style.width) == maxW) { + this.wDone = true; + for (var i = 0; i < this.resizeWTimerCount; i++) { window.clearTimeout(this.resizeWTimerArray[i]); } + } +}; +LyteBox.prototype.resizeH = function(id, curH, maxH, pixelrate, speed) { + var timer = speed ? speed : (this.resizeDuration/2); + var object = this.doc.getElementById(id); + var newH = (this.doAnimations ? curH : maxH); + object.style.height = (newH) + "px"; + if (newH < maxH) { + newH += (newH + pixelrate >= maxH) ? (maxH - newH) : pixelrate; + } else if (newH > maxH) { + newH -= (newH - pixelrate <= maxH) ? (newH - maxH) : pixelrate; + } + this.resizeHTimerArray[this.resizeHTimerCount++] = setTimeout("myLytebox.resizeH('" + id + "', " + newH + ", " + maxH + ", " + pixelrate + ", " + (timer+.02) + ")", timer+.02); + if (parseInt(object.style.height) == maxH) { + this.hDone = true; + for (var i = 0; i < this.resizeHTimerCount; i++) { window.clearTimeout(this.resizeHTimerArray[i]); } + } +}; +LyteBox.prototype.getPageScroll = function() { + if (self.pageYOffset) { + return this.isFrame ? parent.pageYOffset : self.pageYOffset; + } else if (this.doc.documentElement && this.doc.documentElement.scrollTop){ + return this.doc.documentElement.scrollTop; + } else if (document.body) { + return this.doc.body.scrollTop; + } +}; +LyteBox.prototype.getPageSize = function() { + var xScroll, yScroll, windowWidth, windowHeight; + if (window.innerHeight && window.scrollMaxY) { + xScroll = this.doc.scrollWidth; + yScroll = (this.isFrame ? parent.innerHeight : self.innerHeight) + (this.isFrame ? parent.scrollMaxY : self.scrollMaxY); + } else if (this.doc.body.scrollHeight > this.doc.body.offsetHeight){ + xScroll = this.doc.body.scrollWidth; + yScroll = this.doc.body.scrollHeight; + } else { + xScroll = this.doc.getElementsByTagName("html").item(0).offsetWidth; + yScroll = this.doc.getElementsByTagName("html").item(0).offsetHeight; + xScroll = (xScroll < this.doc.body.offsetWidth) ? this.doc.body.offsetWidth : xScroll; + yScroll = (yScroll < this.doc.body.offsetHeight) ? this.doc.body.offsetHeight : yScroll; + } + if (self.innerHeight) { + windowWidth = (this.isFrame) ? parent.innerWidth : self.innerWidth; + windowHeight = (this.isFrame) ? parent.innerHeight : self.innerHeight; + } else if (document.documentElement && document.documentElement.clientHeight) { + windowWidth = this.doc.documentElement.clientWidth; + windowHeight = this.doc.documentElement.clientHeight; + } else if (document.body) { + windowWidth = this.doc.getElementsByTagName("html").item(0).clientWidth; + windowHeight = this.doc.getElementsByTagName("html").item(0).clientHeight; + windowWidth = (windowWidth == 0) ? this.doc.body.clientWidth : windowWidth; + windowHeight = (windowHeight == 0) ? this.doc.body.clientHeight : windowHeight; + } + var pageHeight = (yScroll < windowHeight) ? windowHeight : yScroll; + var pageWidth = (xScroll < windowWidth) ? windowWidth : xScroll; + return new Array(pageWidth, pageHeight, windowWidth, windowHeight); +}; +LyteBox.prototype.toggleFlash = function(state) { + var objects = this.doc.getElementsByTagName("object"); + for (var i = 0; i < objects.length; i++) { + objects[i].style.visibility = (state == "hide") ? 'hidden' : 'visible'; + } + var embeds = this.doc.getElementsByTagName("embed"); + for (var i = 0; i < embeds.length; i++) { + embeds[i].style.visibility = (state == "hide") ? 'hidden' : 'visible'; + } + if (this.isFrame) { + for (var i = 0; i < parent.frames.length; i++) { + try { + objects = parent.frames[i].window.document.getElementsByTagName("object"); + for (var j = 0; j < objects.length; j++) { + objects[j].style.visibility = (state == "hide") ? 'hidden' : 'visible'; + } + } catch(e) { } + try { + embeds = parent.frames[i].window.document.getElementsByTagName("embed"); + for (var j = 0; j < embeds.length; j++) { + embeds[j].style.visibility = (state == "hide") ? 'hidden' : 'visible'; + } + } catch(e) { } + } + } +}; +LyteBox.prototype.toggleSelects = function(state) { + var selects = this.doc.getElementsByTagName("select"); + for (var i = 0; i < selects.length; i++ ) { + selects[i].style.visibility = (state == "hide") ? 'hidden' : 'visible'; + } + if (this.isFrame) { + for (var i = 0; i < parent.frames.length; i++) { + try { + selects = parent.frames[i].window.document.getElementsByTagName("select"); + for (var j = 0; j < selects.length; j++) { + selects[j].style.visibility = (state == "hide") ? 'hidden' : 'visible'; + } + } catch(e) { } + } + } +}; +LyteBox.prototype.pause = function(numberMillis) { + var now = new Date(); + var exitTime = now.getTime() + numberMillis; + while (true) { + now = new Date(); + if (now.getTime() > exitTime) { return; } + } +}; +if (window.addEventListener) { + window.addEventListener("load",initLytebox,false); +} else if (window.attachEvent) { + window.attachEvent("onload",initLytebox); +} else { + window.onload = function() {initLytebox();} +} +function initLytebox() { myLytebox = new LyteBox(); } \ No newline at end of file diff --git a/plugins/tidypics/views/default/annotation/annotate.php b/plugins/tidypics/views/default/annotation/annotate.php new file mode 100644 index 0000000000000000000000000000000000000000..8156a4bb4ad47dccdbcb97a3cd08cfe1985dfe8a --- /dev/null +++ b/plugins/tidypics/views/default/annotation/annotate.php @@ -0,0 +1,21 @@ +<?php + + /* + * Overriding core view to work around bug dealing with empty titles + */ + + $performed_by = get_entity($vars['item']->subject_guid); + $object = get_entity($vars['item']->object_guid); + $url = $object->getURL(); + $subtype = get_subtype_from_id($object->subtype); + $title = $object->title; + if (!$title) + $title = elgg_echo('untitled'); + + $url = "<a href=\"{$performed_by->getURL()}\">{$performed_by->name}</a>"; + $string = sprintf(elgg_echo("river:posted:generic"),$url) . " "; + $string .= elgg_echo("{$subtype}:river:annotate") . " <a href=\"" . $object->getURL() . "\">" . $title . "</a>"; + +?> + +<?php echo $string; ?> \ No newline at end of file diff --git a/plugins/tidypics/views/default/object/album.php b/plugins/tidypics/views/default/object/album.php new file mode 100644 index 0000000000000000000000000000000000000000..85dd69ac9d56cdc0e399d05d4d21e77672f854a7 --- /dev/null +++ b/plugins/tidypics/views/default/object/album.php @@ -0,0 +1,161 @@ +<?php + /** + * Tidypics Album Gallery View + */ + + global $CONFIG; + + $album = $vars['entity']; + $album_guid = $album->getGUID(); + $owner = $album->getOwnerEntity(); + $tags = $album->tags; + $title = $album->title; + $desc = $album->description; + $friendlytime = friendly_time($album->time_created); + $mime = $album->mimetype; + + if (get_context() == "search") { + + if (get_input('search_viewtype') == "gallery") { + +/****************************************************************************** + * + * Gallery view of an album object + * + * This is called when looking at page of albums + * + * + *****************************************************************************/ + + //get album cover if one was set + if ($album->cover) + $album_cover = '<img src="' . $vars['url'] . 'pg/photos/thumbnail/' . $album->cover . '/small/" class="tidypics_album_cover" alt="' . $title . '"/>'; + else + $album_cover = '<img src="' . $vars['url'] . 'mod/tidypics/graphics/empty_album.png" class="tidypics_album_cover" alt="new album">'; + +?> +<div class="tidypics_album_gallery_item"> + <div class="tidypics_gallery_title"> + <a href="<?php echo $album->getURL();?>"><?php echo $title;?></a> + </div> + <a href="<?php echo $album->getURL();?>"><?php echo $album_cover;?></a><br> + <small><a href="<?php echo $vars['url'];?>pg/profile/<?php echo $owner->username;?>"><?php echo $owner->name;?></a> + <br /><?php echo $friendlytime;?><br /> +<?php + //get the number of comments + $numcomments = elgg_count_comments($album); + if ($numcomments) + echo "<a href=\"{$album->getURL()}\">" . sprintf(elgg_echo("comments")) . " (" . $numcomments . ")</a>"; +?> + </small> +</div> +<?php + } else { +/****************************************************************************** + * + * List view of an album object + * + * This is called when an album object is returned in a search. + * + * + *****************************************************************************/ + + $info = '<p><a href="' . $album->getURL() . '">' . $title . '</a></p>'; + $info .= "<p class=\"owner_timestamp\"><a href=\"{$vars['url']}pg/profile/{$owner->username}\">{$owner->name}</a> {$friendlytime}"; + $numcomments = elgg_count_comments($album); + if ($numcomments) + $info .= ", <a href=\"{$album->getURL()}\">" . sprintf(elgg_echo("comments")) . " (" . $numcomments . ")</a>"; + $info .= "</p>"; + + //get album cover if one was set + if ($album->cover) + $icon = "<a href=\"{$album->getURL()}\">" . '<img src="' . $vars['url'] . 'mod/tidypics/thumbnail.php?file_guid=' . $album->cover . '&size=thumb" alt="thumbnail" /></a>'; + else + $icon = "<a href=\"{$album->getURL()}\">" . '<img src="' . $vars['url'] . 'mod/tidypics/graphics/image_error_thumb.png" alt="new album"></a>'; + + echo elgg_view_listing($icon, $info); + } + } else { + +/****************************************************************************** + * + * Individual view of an album object + * + * This is called when getting a listing of the photos in an album + * + * + *****************************************************************************/ + + $page = get_input("page"); + list($album_placeholder, $album_id, $album_title) = split("/", $page); + + $photo_ratings = get_plugin_setting('photo_ratings', 'tidypics'); + if ($photo_ratings == "enabled") + add_submenu_item( elgg_echo("tidypics:highestrated"), + $CONFIG->wwwroot . "pg/photos/highestrated/group:" . $album_id, + 'photos'); + + echo elgg_view_title($title); +?> +<div class="contentWrapper"> + <div id="tidypics_breadcrumbs"> + <?php echo elgg_view('tidypics/breadcrumbs', array() ); ?> + </div> +<?php + echo '<div id="tidypics_desc">' . autop($desc) . '</div>'; + + $images = get_entities("object", "image", $album_guid, '', 999); + + //build array for back | next links + $_SESSION['image_sort'] = array(); + + if (is_array($images)) { + foreach ($images as $image) { + array_push($_SESSION['image_sort'], $image->guid); + } + + // display the simple image views. Uses 'object/image' view + echo list_entities("object", "image", $album_guid, 24, false); + + $num_images = count($images); + } else { + echo '<div class="tidypics_info">' . elgg_echo('image:none') . '</div>'; + $num_images = 0; + } + +?> + <div class="clearfloat"></div> + <div class="tidypics_info"> +<?php + + if (!is_null($tags)) { +?> + <div class="object_tag_string"><?php echo elgg_view('output/tags',array('value' => $tags));?></div> +<?php + } +?> + <?php echo elgg_echo('album:by');?> <b><a href="<?php echo $vars['url'] ;?>pg/profile/<?php echo $owner->username; ?>"><?php echo $owner->name; ?></a></b> <?php echo $friendlytime; ?><br> + <?php echo elgg_echo('image:total');?> <b><?php echo $num_images; ?></b><br> +<?php + $categories = elgg_view('categories/view',$vars); + if (!empty($categories)) { +?> + <br /> +<b><?php echo elgg_echo('categories'); ?>:</b> + <?php + + echo $categories; + + } +?> + </div> + +<?php + + if ($vars['full']) { + echo elgg_view_comments($album); + } + + echo '</div>'; + } // end of individual album view +?> diff --git a/plugins/tidypics/views/default/object/image.php b/plugins/tidypics/views/default/object/image.php new file mode 100644 index 0000000000000000000000000000000000000000..ee81d800fe3efa6420252eddb625419a8007b7f4 --- /dev/null +++ b/plugins/tidypics/views/default/object/image.php @@ -0,0 +1,231 @@ +<?php + /** + * + * Tidypics image object views + */ + + global $CONFIG; + include_once dirname(dirname(dirname(dirname(__FILE__)))) . "/lib/exif.php"; + + $image = $vars['entity']; + $image_guid = $image->getGUID(); + $tags = $image->tags; + $title = $image->title; + $desc = $image->description; + $owner = $image->getOwnerEntity(); + $friendlytime = friendly_time($image->time_created); + + +/******************************************************************** + * + * search view of an image + * + ********************************************************************/ + if (get_context() == "search") { + + // gallery view is a matrix view showing just the image - size: small + if (get_input('search_viewtype') == "gallery") { + ?> + <div class="tidypics_album_images"> + <a href="<?php echo $image->getURL();?>"><img src="<?php echo $vars['url'];?>mod/tidypics/thumbnail.php?file_guid=<?php echo $image_guid;?>&size=small" alt="thumbnail"/></a> + </div> + <?php + } + else{ + // list view displays a thumbnail icon of the image, its title, and the number of comments + $info = '<p><a href="' .$image->getURL(). '">'.$title.'</a></p>'; + $info .= "<p class=\"owner_timestamp\"><a href=\"{$vars['url']}pg/profile/{$owner->username}\">{$owner->name}</a> {$friendlytime}"; + $numcomments = elgg_count_comments($image); + if ($numcomments) + $info .= ", <a href=\"{$image->getURL()}\">" . sprintf(elgg_echo("comments")) . " (" . $numcomments . ")</a>"; + $info .= "</p>"; + $icon = "<a href=\"{$image->getURL()}\">" . '<img src="' . $vars['url'] . 'mod/tidypics/thumbnail.php?file_guid=' . $image_guid . '&size=thumb" alt="' . $title . '" /></a>'; + + echo elgg_view_listing($icon, $info); + } + +/*************************************************************** + * + * front page view + * + ****************************************************************/ + } else if (get_context() == "front") { + // the front page view is a clikcable thumbnail of the image +?> +<a href="<?php echo $image->getURL(); ?>"> +<img src="<?php echo $vars['url'];?>mod/tidypics/thumbnail.php?file_guid=<?php echo $image_guid;?>&size=thumb" class="tidypics_album_cover" alt="<?php echo $title; ?>" title="<?php echo $title; ?>" /> +</a> +<?php + } else { + +/******************************************************************** + * + * listing of photos in an album + * + *********************************************************************/ + if (!$vars['full']) { + +?> +<?php + // plugins can override the image link to add lightbox code here + $image_html = false; + $image_html = trigger_plugin_hook('tp_thumbnail_link', 'album', array('image' => $image), $image_html); + + if ($image_html) { + echo $image_html; + } else { + // default link to image if no one overrides +?> + <div class="tidypics_album_images"> + <a href="<?php echo $image->getURL();?>"><img src="<?php echo $vars['url'];?>pg/photos/thumbnail/<?php echo $image_guid;?>/small/" alt="<?php echo $image->title; ?>"/></a> + </div> +<?php + } +?> +<?php + } else { + +/******************************************************************** + * + * tidypics individual image display + * + *********************************************************************/ + + + $viewer = get_loggedin_user(); + + + // Build back and next links + $back = ''; + $next = ''; + + $album = get_entity($image->container_guid); + + $current = array_search($image_guid, $_SESSION['image_sort']); + + if (!$current) { // means we are no longer using the correct album array + + //rebuild the array + $count = get_entities("object","image", $album->guid, '', 999); + $_SESSION['image_sort'] = array(); + + foreach ($count as $img) { + array_push($_SESSION['image_sort'], $img->guid); + } + + if ($_SESSION['image_sort']) + $current = array_search($image_guid, $_SESSION['image_sort']); + } + + if ($current != 0) + $back = '<a href="' .$vars['url'] . 'pg/photos/view/' . $_SESSION['image_sort'][$current-1] . '">« ' . elgg_echo('image:back') . '</a>'; + + if (sizeof($_SESSION['image_sort']) > $current + 1) + $next = '<a href="' . $vars['url'] . 'pg/photos/view/' . $_SESSION['image_sort'][$current+1] . '">' . elgg_echo('image:next') . ' »</a>'; + + +?> +<div class="contentWrapper"> + <div id="tidypics_wrapper"> + + <div id="tidypics_breadcrumbs"> + <?php echo elgg_view('tidypics/breadcrumbs', array('album' => $album,) ); ?> <br /> + <?php + if (get_plugin_setting('view_count', 'tidypics') != "disabled") { + + $image->addView($viewer->guid); + $views = $image->getViews($viewer->guid); + if (is_array($views)) { + echo sprintf(elgg_echo("tidypics:views"), $views['total']); + if ($owner->guid == $viewer->guid) { + echo ' ' . sprintf(elgg_echo("tidypics:viewsbyowner"), $views['unique']); + } + else { + if ($views['mine']) + echo ' ' . sprintf(elgg_echo("tidypics:viewsbyothers"), $views['mine']); + } + } + } + ?> + </div> + + <div id="tidypics_desc"> + <?php echo autop($desc); ?> + </div> + <div id="tidypics_image_nav"> + <ul> + <li><?php echo $back; ?></li> + <li><?php echo $next; ?></li> + </ul> + </div> + <div id="tidypics_image_wrapper"> + <?php + // this code controls whether the photo is a hyperlink or not and what it links to + if (get_plugin_setting('download_link', 'tidypics') != "disabled") { + // admin allows downloads so default to inline download link + $image_html = "<a href=\"{$vars['url']}pg/photos/download/{$image_guid}/inline/\" title=\"{$title}\" >"; + $image_html .= "<img id=\"tidypics_image\" src=\"{$vars['url']}pg/photos/thumbnail/{$image_guid}/large/\" alt=\"{$title}\" />"; + $image_html .= "</a>"; + } else { + $image_html = "<img id=\"tidypics_image\" src=\"{$vars['url']}pg/photos/thumbnail/{$image_guid}/large/\" alt=\"{$title}\" />"; + } + // does any plugin want to override the link + $image_html = trigger_plugin_hook('tp_thumbnail_link', 'image', array('image' => $image), $image_html); + echo $image_html; + ?> + <div class="clearfloat"></div> + </div> +<?php + // image menu (start tagging, download, etc.) + + echo '<div id="tidypics_controls"><ul>'; + echo elgg_view('tidypics/image_menu', array('image_guid' => $image_guid, + 'viewer' => $viewer, + 'owner' => $owner, + 'anytags' => $image->isPhotoTagged(), + 'album' => $album, ) ); + echo '</ul></div>'; + + // tagging code - photo tags on images, photo tag listing and hidden divs used in tagging + if (get_plugin_setting('tagging', 'tidypics') != "disabled") { + echo elgg_view('tidypics/tagging', array( 'image' => $image, + 'viewer' => $viewer, + 'owner' => $owner, ) ); + } + + + if (get_plugin_setting('exif', 'tidypics') == "enabled") { +?> + <?php echo elgg_view('tidypics/exif', array('guid'=> $image_guid)); ?> +<?php } ?> + <div class="tidypics_info"> +<?php if (!is_null($tags)) { ?> + <div class="object_tag_string"><?php echo elgg_view('output/tags',array('value' => $tags));?></div> +<?php } + if (get_plugin_setting('photo_ratings', 'tidypics') == "enabled") { +?> + <div id="rate_container"> + <?php echo elgg_view('rate/rate', array('entity'=> $vars['entity'])); ?> +</div> +<?php + } + + echo elgg_echo('image:by');?> <b><a href="<?php echo $vars['url']; ?>pg/profile/<?php echo $owner->username; ?>"><?php echo $owner->name; ?></a></b> <?php echo $friendlytime; +?> + </div> + </div> <!-- tidypics wrapper--> +<?php + + echo elgg_view_comments($image); + + echo '<div class="clearfloat"></div>'; + + echo '</div>'; // content wrapper + + } // end of individual image display + + } + +?> + + diff --git a/plugins/tidypics/views/default/river/object/album/create.php b/plugins/tidypics/views/default/river/object/album/create.php new file mode 100644 index 0000000000000000000000000000000000000000..20f9293d73b2c70996b6e089c17a81c6c646daa6 --- /dev/null +++ b/plugins/tidypics/views/default/river/object/album/create.php @@ -0,0 +1,42 @@ +<?php + + $performed_by = get_entity($vars['item']->subject_guid); + $album = get_entity($vars['item']->object_guid); + + $group_album = ($album->owner_guid != $album->container_guid); + if ($group_album) { + $group = get_entity($album->container_guid); + $group_name = $group->name; + $group_link = $group->getURL(); + } + + $url = "<a href=\"{$performed_by->getURL()}\">{$performed_by->name}</a>"; + $string = sprintf(elgg_echo("album:river:created"),$url) . " "; + $string .= "<a href=\"" . $album->getURL() . "\">" . $album->title . "</a>"; + if ($group_album) + $string .= ' ' . elgg_echo('album:river:group') . ' ' . "<a href=\"{$group_link}\" >{$group_name}</a>"; + + $album_river_view = get_plugin_setting('album_river_view', 'tidypics'); + + if ($album_river_view == "cover") { + if ($album->cover) { + $string .= "<div class=\"river_content\"> <img src=\"" . $CONFIG->wwwroot . 'mod/tidypics/thumbnail.php?file_guid=' . $album->cover . '&size=thumb" class="tidypics_album_cover" alt="thumbnail"/>' . "</div>"; + } + } else { + + $string .= "<div class=\"river_content\">"; + + $images = get_entities("object", "image", $album->guid, 'time_created desc', 7); + + if (count($images)) { + foreach($images as $image){ + $string .= "<a href=\"" . $image->getURL() . "\"> <img src=\"" . $CONFIG->wwwroot . 'mod/tidypics/thumbnail.php?file_guid=' . $image->guid . '&size=thumb" class="tidypics_album_cover" alt="thumbnail"/> </a>'; + } + } + + $string .= "</div>"; + } + +echo $string; + +?> diff --git a/plugins/tidypics/views/default/river/object/image/create.php b/plugins/tidypics/views/default/river/object/image/create.php new file mode 100644 index 0000000000000000000000000000000000000000..2f1777f642175705859f41a74a52463bdc110a5f --- /dev/null +++ b/plugins/tidypics/views/default/river/object/image/create.php @@ -0,0 +1,29 @@ +<?php + + $performed_by = get_entity($vars['item']->subject_guid); + $image = get_entity($vars['item']->object_guid); + if($image->title) { + $title = $image->title; + } else { + $title = "untitled"; + } + + $url = "<a href=\"{$performed_by->getURL()}\">{$performed_by->name}</a>"; + $album = get_entity($image->container_guid); + + $album_link = "<a href='". $album->getURL() . "'>" . $album->title . "</a>"; + $image_link = "<a href=\"" . $image->getURL() . "\">" . $title . "</a>"; + + $string = sprintf(elgg_echo("image:river:created"),$performed_by->name, $image_link, $album_link); + + $string .= "<div class=\"river_content\">"; + +/* // this adds the album cover to the river display + $string .= "<a href=\"" . $album->getURL() . "\"> <img src=\"" . $CONFIG->wwwroot . 'mod/tidypics/thumbnail.php?file_guid=' . $album->cover . '&size=thumb" class="tidypics_album_cover" alt="thumbnail"/> </a>'; +*/ + $string .= "<a href=\"" . $image->getURL() . "\"> <img src=\"" . $CONFIG->wwwroot . 'mod/tidypics/thumbnail.php?file_guid=' . $image->guid . '&size=thumb" class="tidypics_album_cover" alt="thumbnail"/> </a>'; + $string .= "</div>"; + + echo $string; + +?> \ No newline at end of file diff --git a/plugins/tidypics/views/default/river/object/image/tag.php b/plugins/tidypics/views/default/river/object/image/tag.php new file mode 100644 index 0000000000000000000000000000000000000000..1b3589afbf23e793fee6b58b52b4fddf779f9bbc --- /dev/null +++ b/plugins/tidypics/views/default/river/object/image/tag.php @@ -0,0 +1,23 @@ +<?php + + $image = get_entity($vars['item']->subject_guid); + $person_tagged = get_entity($vars['item']->object_guid); + if($image->title) { + $title = $image->title; + } else { + $title = "untitled"; + } + + // viewer may not have permission to view image + if (!$image) + return; + + + $image_url = "<a href=\"{$image->getURL()}\">{$title}</a>"; + $person_url = "<a href=\"{$person_tagged->getURL()}\">{$person_tagged->name}</a>"; + + $string = $person_url . ' ' . elgg_echo('image:river:tagged') . ' ' . $image_url; + + echo $string; + +?> \ No newline at end of file diff --git a/plugins/tidypics/views/default/settings/tidypics/edit.php b/plugins/tidypics/views/default/settings/tidypics/edit.php new file mode 100644 index 0000000000000000000000000000000000000000..eb391c8bccd58a295a6a7e1cf56ac86eaf9225a0 --- /dev/null +++ b/plugins/tidypics/views/default/settings/tidypics/edit.php @@ -0,0 +1,12 @@ +<?php + global $CONFIG; + $system_url = $CONFIG->wwwroot . 'mod/tidypics/pages/server_analysis.php'; + $settings_url = $CONFIG->wwwroot . 'mod/tidypics/pages/admin.php'; +?> + +<p> +<a href="<?php echo $system_url; ?>">Run Server Analysis</a> +</p> +<p> +<a href="<?php echo $settings_url; ?>">Change Tidypics Settings</a> +</p> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/admin/help.php b/plugins/tidypics/views/default/tidypics/admin/help.php new file mode 100644 index 0000000000000000000000000000000000000000..7f871598c29c590fbd28b359652729051058d2b2 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/admin/help.php @@ -0,0 +1,25 @@ +<br /> +<h3>White screen when uploading images</h3> +<p> +Tidypics tries to calculate the maximum size of an image that your server will support. If it +guesses incorrectly and someone uploads a photo that is too large, the script may crash when +resizing the image if you are using GD. The easiest way to test this is to set display_errors +to 1 in your .htaccess file and upload large images. If this causes a problem, a php memory error +should display on the screen. You can increased your php memory limit (see the docs directory). +A better option is to use ImageMagick if your server supports it (again see the docs directory). +</p><p> +If it is not a memory issue, you should see some other error appear. Once you have fixed the error, +change display_error back to 0. +</p> +<h3>Question mark images appear</h3> +<p> +If you see question mark images when you look at your albums, this means the resizing of the images +failed. This could be due to the memory limits as described above. There are other causes. Tidypics +tries to detect these problems and write the cause to the error log. You should check your server +error log right after an upload that results in a question mark for these error messages. The messages +will begin with "Tidypics warning:". It is possible if you have turned off php warnings that you will +not see these warnings. +</p><p> +Another possible cause is using ImageMagick when your server does not support it or specifying +the wrong path to the ImageMagick executables. +</p> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/admin/imagelib.php b/plugins/tidypics/views/default/tidypics/admin/imagelib.php new file mode 100644 index 0000000000000000000000000000000000000000..b4656afe1a61b24c3f3cea4caaf8c61d52e0e9cc --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/admin/imagelib.php @@ -0,0 +1,62 @@ +<?php + + $img_type = get_subtype_id('object', 'image'); + $query = "SELECT count(guid) as total from {$CONFIG->dbprefix}entities where subtype={$img_type}"; + $total = get_data_row($query); + $num_images = $total->total; + + $img_type = get_subtype_id('object', 'album'); + $query = "SELECT count(guid) as total from {$CONFIG->dbprefix}entities where subtype={$img_type}"; + $total = get_data_row($query); + $num_albums = $total->total; + + $num_comments_photos = count_annotations(0, 'object', 'image', 'generic_comment'); + $num_comments_albums = count_annotations(0, 'object', 'album', 'generic_comment'); + + $num_views = count_annotations(0, 'object', 'image', 'tp_view'); + + if (get_plugin_setting('tagging', 'tidypics') != "disabled") + $num_tags = count_annotations(0, 'object', 'image', 'phototag'); +?> +<br /> +<h3>Overview</h3> +<p> +An image library is required by Tidypics to perform various manipulations: resizing on upload, watermarking, rotation, and cropping. +There are three image library options with Tidypics: PHP extension <a href="http://www.php.net/manual/en/book.image.php">GD</a>, +<a href="http://www.imagemagick.org/">ImageMagick</a> called via a system call, and the PHP extension +<a href="http://pecl.php.net/package/imagick/">imagick</a>. GD is the most common of the three on hosted servers but suffers +from serious memory usage problems when resizing photos. If you have access to ImageMagick (whether through system calls or the +PHP extension), we recommend that you use that. +</p> +<h3>Testing ImageMagick Commandline</h3> +<p> +To use the ImageMagick executables, PHP must be configured to allow calls to exec(). You can check our +<a href="<?php echo $CONFIG->wwwroot . 'mod/tidypics/pages/server_analysis.php'; ?>">server analysis page</a> to find out the +configuration of your server. Next, you need to determine the path to ImageMagick on your server. Your hosting service should +be able to provide this to you. You can test if the location is correct below. If successful, it should display the version of +ImageMagick installed on your server. +</p> +<br /> +<p> +<?php echo elgg_echo('tidypics:settings:im_path'); ?><br /> +<input name="im_location" type="text" /> +<input type="submit" value="Submit" onclick="TestImageMagickLocation();" /> +</p> +<div id="im_results"></div> + +<script type="text/javascript"> +function TestImageMagickLocation() +{ + var loc = $('input[name=im_location]').val(); + $("#im_results").html(""); + $.ajax({ + type: "GET", + url: "<?php echo $CONFIG->wwwroot . 'mod/tidypics/actions/imtest.php'; ?>", + data: {location: loc}, + cache: false, + success: function(html){ + $("#im_results").html(html); + } + }); +} +</script> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/admin/settings.php b/plugins/tidypics/views/default/tidypics/admin/settings.php new file mode 100644 index 0000000000000000000000000000000000000000..ff7d330e259a7a2824437d88044ea7b355891338 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/admin/settings.php @@ -0,0 +1,25 @@ +<?php + + echo elgg_view('output/longtext', array('value' => elgg_echo("tidypics:admin:instructions"))); + + global $CONFIG; + $system_url = $CONFIG->wwwroot . 'mod/tidypics/pages/server_analysis.php'; + $upgrade_url = $CONFIG->wwwroot . 'mod/tidypics/actions/upgrade.php'; + + $upgrade = false; + if (!get_subtype_class('object', 'image') || !get_subtype_class('object', 'album')) + $upgrade = true; +?> +<p> +<?php + if ($upgrade) { +?> +<a href="<?php echo $upgrade_url; ?>">Upgrade</a><br /> +<?php + } +?> +<a href="<?php echo $system_url; ?>">Run Server Analysis</a> +</p> +<?php + echo elgg_view("tidypics/forms/settings"); +?> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/admin/stats.php b/plugins/tidypics/views/default/tidypics/admin/stats.php new file mode 100644 index 0000000000000000000000000000000000000000..aea5e75ba918aed3aa3ff43b87cbbc1996845e58 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/admin/stats.php @@ -0,0 +1,35 @@ +<?php + + $img_type = get_subtype_id('object', 'image'); + $query = "SELECT count(guid) as total from {$CONFIG->dbprefix}entities where subtype={$img_type}"; + $total = get_data_row($query); + $num_images = $total->total; + + $img_type = get_subtype_id('object', 'album'); + $query = "SELECT count(guid) as total from {$CONFIG->dbprefix}entities where subtype={$img_type}"; + $total = get_data_row($query); + $num_albums = $total->total; + + $num_comments_photos = count_annotations(0, 'object', 'image', 'generic_comment'); + $num_comments_albums = count_annotations(0, 'object', 'album', 'generic_comment'); + + $num_views = count_annotations(0, 'object', 'image', 'tp_view'); + + if (get_plugin_setting('tagging', 'tidypics') != "disabled") + $num_tags = count_annotations(0, 'object', 'image', 'phototag'); +?> +<p> +<br /> +Photos: <?php echo $num_images; ?><br /> +Albums: <?php echo $num_albums; ?><br /> +Comments on photos: <?php echo $num_comments_photos; ?><br /> +Comments on albums: <?php echo $num_comments_albums; ?><br /> +Total views: <?php echo $num_views; ?><br /> +<?php + if ($num_tags) { +?> +Photo tags: <?php echo $num_tags; ?><br /> +<?php + } +?> +</p> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/admin/thumbnails.php b/plugins/tidypics/views/default/tidypics/admin/thumbnails.php new file mode 100644 index 0000000000000000000000000000000000000000..ccd8840059c7de1aa2396d4df4e42bc325f91a24 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/admin/thumbnails.php @@ -0,0 +1,33 @@ +<br /> +<h3>Overview</h3> +<p> +This page allows you to create thumbnails for images when the thumbnail creation failed during upload. +You may experience problems with thumbnail creation if your image library in not configured properly or +if there is not enough memory for the GD library to load and resize an image. If your users have +experienced problems with thumbnail creation and you have modified your setup, you can try to redo the +thumbnails. Find the unique identifier of the photo (it is the number near the end of the url when viewing +a photo) and enter it below. +</p> +<h3>Thumbnail Creation</h3> +<p> +<b><?php echo elgg_echo('tidypics:settings:im_id'); ?></b>: +<input name="image_id" type="text" /> +<input type="submit" value="Submit" onclick="TestThumbnailCreation();" /> +</p> +<div id="im_results"></div> +<script type="text/javascript"> +function TestThumbnailCreation() +{ + var image_id = $('input[name=image_id]').val(); + $("#im_results").html(""); + $.ajax({ + type: "GET", + url: "<?php echo $CONFIG->wwwroot . 'mod/tidypics/actions/create_thumbnails.php'; ?>", + data: {guid: image_id}, + cache: false, + success: function(html){ + $("#im_results").html(html); + } + }); +} +</script> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/admin/tidypics.php b/plugins/tidypics/views/default/tidypics/admin/tidypics.php new file mode 100644 index 0000000000000000000000000000000000000000..fa518156ca178852721dce52586687023ceae267 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/admin/tidypics.php @@ -0,0 +1,60 @@ +<?php + + global $CONFIG; + + $tab = $vars['tab']; + + $settingsselect = ''; + $statsselect = ''; + $imagelibselect = ''; + $thumbnailselect = ''; + $helpselect = ''; + switch($tab) { + case 'settings': + $settingsselect = 'class="selected"'; + break; + case 'stats': + $statsselect = 'class="selected"'; + break; + case 'imagelib': + $imagelibselect = 'class="selected"'; + break; + case 'thumbnail': + $thumbnailselect = 'class="selected"'; + break; + case 'help': + $helpselect = 'class="selected"'; + break; + } + +?> +<div class="contentWrapper"> + <div id="elgg_horizontal_tabbed_nav"> + <ul> + <li <?php echo $settingsselect; ?>><a href="<?php echo $CONFIG->wwwroot . 'mod/tidypics/pages/admin.php?tab=settings'; ?>"><?php echo elgg_echo('tidypics:settings'); ?></a></li> + <li <?php echo $statsselect; ?>><a href="<?php echo $CONFIG->wwwroot . 'mod/tidypics/pages/admin.php?tab=stats'; ?>"><?php echo elgg_echo('tidypics:stats'); ?></a></li> + <li <?php echo $imagelibselect; ?>><a href="<?php echo $CONFIG->wwwroot . 'mod/tidypics/pages/admin.php?tab=imagelib'; ?>"><?php echo elgg_echo('tidypics:settings:image_lib'); ?></a></li> + <li <?php echo $thumbnailselect; ?>><a href="<?php echo $CONFIG->wwwroot . 'mod/tidypics/pages/admin.php?tab=thumbnail'; ?>"><?php echo elgg_echo('tidypics:settings:thumbnail'); ?></a></li> + <li <?php echo $helpselect; ?>><a href="<?php echo $CONFIG->wwwroot . 'mod/tidypics/pages/admin.php?tab=help'; ?>"><?php echo elgg_echo('tidypics:settings:help'); ?></a></li> + </ul> + </div> +<?php + switch($tab) { + case 'settings': + echo elgg_view("tidypics/admin/settings"); + break; + case 'stats': + echo elgg_view("tidypics/admin/stats"); + break; + case 'imagelib': + echo elgg_view("tidypics/admin/imagelib"); + break; + case 'thumbnail': + echo elgg_view("tidypics/admin/thumbnails"); + break; + case 'help': + echo elgg_view("tidypics/admin/help"); + break; + } +?> +</div> diff --git a/plugins/tidypics/views/default/tidypics/albums.php b/plugins/tidypics/views/default/tidypics/albums.php new file mode 100644 index 0000000000000000000000000000000000000000..42ac15afede2e3a7f649b598063cc4c5a9da1b40 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/albums.php @@ -0,0 +1,51 @@ +<?php + + //the number of albums to display + $number = (int)$vars['num_albums']; + if (!$number) + $number = 5; + + $owner = page_owner_entity(); + $owner_albums = get_entities("object", "album", page_owner(), "", $number, 0, false); + + echo '<div id="tidypics_album_widget_container">'; + + if ($owner_albums) { + foreach($owner_albums as $album) { + + if($album->cover) + $album_cover = '<img src="'.$vars['url'].'mod/tidypics/thumbnail.php?file_guid='.$album->cover.'&size=small" class="tidypics_album_cover" alt="' . $album->title . '"/>'; + else + $album_cover = '<img src="'.$vars['url'].'mod/tidypics/graphics/empty_album.png" class="tidypics_album_cover" alt="' . $album->title . '">'; +?> + <div class="tidypics_album_widget_single_item"> + <div class="tidypics_album_widget_title"><a href="<?php echo $album->getURL();?>"><?php echo $album->title;?></a></div> + <div class="tidypics_album_widget_timestamp"> <?php echo elgg_echo("album:created:on") . ' ' . friendly_time($album->time_created);?></div> +<?php + //get the number of comments + $numcomments = elgg_count_comments($album); + if ($numcomments) + echo "<a href=\"{$album->getURL()}\">" . sprintf(elgg_echo("comments")) . " (" . $numcomments . ")</a><br>"; +?> + <a href="<?php echo $album->getURL();?>"><?php echo $album_cover;?></a> + </div> +<?php + } //end of foreach loop + + // bottom link to all group/user albums + if (is_null($owner->username) || empty($owner->username)) { + echo '<p class="profile_info_edit_buttons"><a href="' . $vars['url'] . 'pg/photos/world">' . elgg_echo('album:all') . '</a></p>'; + } else { + echo '<p class="tidypics_download"><a href="' . $vars['url'] . 'pg/photos/owned/' . $owner->username . '">' . elgg_echo('album:more') . '</a></p>'; + } + + } + + if (can_write_to_container(0, $owner->guid)) { + echo '<p class="tidypics_download"><a href=' . $CONFIG->wwwroot .'pg/photos/new/' . $owner->username . '>' . elgg_echo("album:create") . '</a></p>'; + } + + + //close album_widget_container div + echo "</div>"; +?> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/breadcrumbs.php b/plugins/tidypics/views/default/tidypics/breadcrumbs.php new file mode 100644 index 0000000000000000000000000000000000000000..c4d347e6e2bcb12bf0e73c8c1c996d7ac76557c6 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/breadcrumbs.php @@ -0,0 +1,22 @@ +<?php + $file_guid = $vars['file_guid']; + $page_owner = page_owner_entity(); + + $first_level_text = ''; + $first_level_link = $CONFIG->wwwroot . "pg/photos/owned/" . $page_owner->username; + if (get_loggedin_userid() == $page_owner->guid) + $first_level_text = elgg_echo('album:yours'); + else + $first_level_text = sprintf(elgg_echo('album:user'), $page_owner->name); +?> +<a href="<?php echo $first_level_link; ?>"><?php echo $first_level_text; ?></a> +<?php + $second_level_text = ''; + if (isset($vars['album'])) { + $second_level_text = $vars['album']->title; + $second_level_link = $vars['album']->getURL(); +?> +>> <a href="<?php echo $second_level_link; ?>"><?php echo $second_level_text; ?></a> +<?php + } +?> diff --git a/plugins/tidypics/views/default/tidypics/content_wrapper.php b/plugins/tidypics/views/default/tidypics/content_wrapper.php new file mode 100644 index 0000000000000000000000000000000000000000..757d069bbba79768245c4dad4651f16887d540c1 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/content_wrapper.php @@ -0,0 +1,10 @@ +<?php + echo elgg_view_title($vars['title']); +?> +<div class="contentWrapper"> +<div class="clearfloat"></div> +<?php + echo $vars['content']; +?> +<div class="clearfloat"></div> +</div> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/css.php b/plugins/tidypics/views/default/tidypics/css.php new file mode 100644 index 0000000000000000000000000000000000000000..9d904a7ff6e50a2d495d8a3d95020bb167b99d86 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/css.php @@ -0,0 +1,301 @@ +<?php + /** + * tidypics CSS extender + */ +?> +/* ---- tidypics object views ---- */ + +#tidypics_wrapper { +} + +#tidypics_breadcrumbs { +margin:5px 0 15px 0; +font-size:80%; +} + +#tidypics_desc { +padding:0 20px; +font-style:italic; +} + +#tidypics_image_nav { +text-align:center; +} + +#tidypics_image_wrapper { +margin:10px 0 10px 0; +text-align:center; +} + +#tidypics_image { +border:1px solid #dedede; +padding:5px; +} + +#tidypics_image_nav ul li { +display:inline; +margin-right:15px; +} + +#tidypics_controls { +text-align:center; +margin-bottom:10px; +} + +#tidypics_controls a { +margin:10px; +} + +#tidypics_controls ul { +list-style:none; +margin:0px; +padding:8px; +} + +#tidypics_controls ul li { +padding:2px 10px 2px 22px; +margin:2px 0px; +display:inline; +} + +.tidypics_info { +padding:20px; +} + +#tidypics_exif { +padding-left:20px; +font-size:80%; +} + +.tidypics_album_images { +float:left; +width:153px; +height:153px; +margin:3px; +padding:4px; +border:1px solid #dedede; +text-align:center; +} + +.tidypics_album_cover { +padding:2px; +border:1px solid #dedede; +margin:5px 0; +} + +.tidypics_album_widget_single_item { +margin-bottom:8px; +} + +.tidypics_album_gallery_item { +float:left; +margin-bottom:20px; +padding: 4px; +text-align:center; +width: 160px; +} + +.tidypics_line_break { +width: 100%; +clear: both; +} + +.tidypics_gallery_title { +font-weight:bold; +} + +.tidypics_popup { +border:1px solid #3B5999; +width:200px; +position:absolute; +z-index:10000; +display:none; +background:#ffffff; +padding:10px; +font-size:12px; +text-align:left; +} + +/* ------ tidypics widget view ------ */ + +#tidypics_album_widget_container { +text-align:center; +} + +.tidypics_album_widget_timestamp { +color:#333333; +} + +.tidypics_widget_latest { +margin: 0 auto; +width: 208px; +} + +/* --------- image upload/edit forms ------------ */ + +#tidpics_image_upload_list li { +margin:3px 0; +} + +.tidypics_edit_image_container { +padding:5px; +margin:5px 0; +overflow:auto; +} + +.tidypics_edit_images { +float:right; +width:160px; +height:160px; +margin:4px; +padding:5px; +border:1px solid #dedede; +text-align:center; +} + +.tidypics_image_info { +float:left; +width:60%; +} + +.tidypics_image_info label { +font-size:1em; +} + +.tidypics_caption_input { + width:98%; + height:100px; +} + +/* ---- tidypics group css ----- */ + +#tidypics_group_profile { +-webkit-border-radius: 8px; +-moz-border-radius: 8px; +background:white none repeat scroll 0 0; +margin:0 0 20px; +padding:0 0 5px; +} + + +/* --------- tidypics river items ------------ */ + +.river_object_image_create { + background: url(<?php echo $vars['url']; ?>mod/tidypics/graphics/icons/river_icon_image.gif) no-repeat left -1px; +} +.river_object_album_create { + background: url(<?php echo $vars['url']; ?>mod/tidypics/graphics/icons/river_icon_album.gif) no-repeat left -1px; +} +.river_object_image_comment { + background: url(<?php echo $vars['url']; ?>_graphics/river_icons/river_icon_comment.gif) no-repeat left -1px; +} +.river_object_album_comment { + background: url(<?php echo $vars['url']; ?>_graphics/river_icons/river_icon_comment.gif) no-repeat left -1px; +} +.river_user_tag { + background: url(<?php echo $vars['url']; ?>mod/tidypics/graphics/icons/river_icon_tag.gif) no-repeat left -1px; +} + +/* ----------- tagging ---------------- */ +#tidypics_tag_instructions { +background:#BBDAF7; +border:1px solid #4690D6; +padding:10px; +height:25px; +min-width:360px; +display:none; +overflow:hidden; +position:absolute; +z-index:10000; +-webkit-border-radius: 8px; +-moz-border-radius: 8px; +} + +#tidypics_tag_instruct_text { +padding-top: 3px; +float: left; +} + +#tidypics_tag_instruct_button_div { +float: left; +margin-left: 15px; +} + +#tidypics_tag_instruct_button { +margin:0; +} + +#tidypics_tag_menu { +width:240px; +max-height:400px; +overflow:hidden; +-webkit-border-radius: 8px; +-moz-border-radius: 8px; +} + +.tidypics_popup_header { +width:100%; +margin-bottom:10px; +} + + +#tidypics_tagmenu_left { +width:175px; +float:left; +} + +#tidypics_tagmenu_right { +float:left; +} + +#tidypics_tagmenu_right .submit_button { +margin-top:2px; +} + +#tidypics_delete_tag_menu { +-webkit-border-radius: 8px; +-moz-border-radius: 8px; +overflow:hidden; +} + +.tidypics_tag { +display:none; +background:url(<?php echo $vars['url']; ?>mod/tidypics/graphics/spacer.gif); +border:2px solid #ffffff; +overflow:hidden; +position:absolute; +z-index:0; +} + +.tidypics_tag_text { +display:none; +overflow:hidden; +position:absolute; +z-index:0; +text-align:center; +background:#BBDAF7; +border:1px solid #3B5999; +-webkit-border-radius:3px; +-moz-border-radius:3px; +padding:1px; +} + +#tidypics_phototags_list { +padding:0 20px 0 20px; +} + +#tidypics_phototags_list ul { +list-style:none; +margin:0px; +padding:8px; +} + +#tidypics_phototags_list ul li { +padding-right:10px; +margin:2px 0px; +display:inline; +} + +#tidypics_image_upload_list { +list-style: none; +} \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/exif.php b/plugins/tidypics/views/default/tidypics/exif.php new file mode 100644 index 0000000000000000000000000000000000000000..0100ac575146ac1b43ba8ee11105f935c0326859 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/exif.php @@ -0,0 +1,14 @@ +<?php + + $guid = $vars['guid']; + + $exif = tp_exif_formatted($guid); + if ($exif) { + echo '<div id="tidypics_exif">'; + foreach ($exif as $name => $value) { + echo $name . ': ' . $value . '<br />'; + } + echo '</div>'; + } + +?> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/forms/edit.php b/plugins/tidypics/views/default/tidypics/forms/edit.php new file mode 100644 index 0000000000000000000000000000000000000000..1758d14f4b9579518a07729cf13f92be9be1f74b --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/forms/edit.php @@ -0,0 +1,128 @@ +<?php + /** + * Tidypics images edit/add form + * This form is used to: + * - create albums + * - edit albums + * - edit images + */ + + //set stuff if we are editing existing album or image + if (isset($vars['entity'])) { + $action = "tidypics/edit"; + $title = $vars['entity']->title; + $body = $vars['entity']->description; + $tags = $vars['entity']->tags; + $access_id = $vars['entity']->access_id; + $subtype = $vars['subtype']; + + // if nothing is sent, create new, but only new albums are sent here + // new images are sent to upload.php + } else { + $action = "tidypics/addalbum"; + $tags = ""; + $title = ""; + $body = ""; + if (defined('ACCESS_DEFAULT')) + $access_id = ACCESS_DEFAULT; + else + $access_id = 1; // logged_in by default + $subtype = 'album'; + + $title = $_SESSION['tidypicstitle']; + $body = $_SESSION['tidypicsbody']; + $tags = $_SESSION['tidypicstags']; + + unset($_SESSION['tidypicstitle']); + unset($_SESSION['tidypicsbody']); + unset($_SESSION['tidypicstags']); + } + + // group or individual + $container_guid = page_owner(); + +?> +<div class="contentWrapper"> + <form action="<?php echo $vars['url']; ?>action/<?php echo $action; ?>" method="post"> + <p> + <label><?php echo elgg_echo('album:title'); ?></label> + <?php echo elgg_view("input/text", array("internalname" => "tidypicstitle", "value" => $title,)); ?> + </p> +<?php + if ($subtype == 'album') { +?> + <p> + <label><?php echo elgg_echo('album:desc'); ?></label> + <?php echo elgg_view("input/longtext",array("internalname" => "tidypicsbody","value" => $body,)); ?> + </p> +<?php + } else { +?> + <p> + <label><?php echo elgg_echo('caption'); ?></label> + <?php echo elgg_view("input/longtext",array("internalname" => "tidypicsbody","value" => $body,"class" => 'tidypics_caption_input')); ?> + </p> +<?php + } +?> + <p> + <label><?php echo elgg_echo("tags"); ?></label> + <?php echo elgg_view("input/tags", array( "internalname" => "tidypicstags","value" => $tags,)); ?> + </p> + +<?php + if ($subtype == 'image') { + $container_guid = $vars['entity']->container_guid; + + // should this image be the cover for the album - only ask for non-cover photos + // determine if it is already the cover + $img_guid = $vars['entity']->guid; + $album = get_entity($container_guid); + $cover_guid = $album->cover; + + if ($cover_guid != $img_guid) { + +?> + <p> +<?php echo elgg_view('input/checkboxes', array('internalname' => "cover", + 'options' => array(elgg_echo("album:cover")), + )); +?> + </p> +<?php + } + + } else { + // album so display access control + + $categories = elgg_view('categories',$vars); + if (!empty($categories)) { +?> + <p> + <?php echo $categories; ?> + </p> + +<?php + } +?> + <p> + <label><?php echo elgg_echo('access'); ?></label> + <?php echo elgg_view('input/access', array('internalname' => 'access_id','value' => $access_id)); ?> + </p> + +<?php + } + + if (isset($vars['entity'])) { +?> + <input type="hidden" name="guid" value="<?php echo $vars['entity']->getGUID(); ?>" /> +<?php + } + + echo elgg_view('input/securitytoken'); +?> + <input type="hidden" name="container_guid" value="<?php echo $container_guid; ?>" /> + <input type="hidden" name="subtype" value="<?php echo $subtype; ?>" /> + <p><input type="submit" name="submit" value="<?php echo elgg_echo('save'); ?>" /></p> + </form> +</div> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/forms/edit_multi.php b/plugins/tidypics/views/default/tidypics/forms/edit_multi.php new file mode 100644 index 0000000000000000000000000000000000000000..4031b796847d58dcd22674f8713e0dadd493c049 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/forms/edit_multi.php @@ -0,0 +1,58 @@ +<?php + /** + * form for mass editing all uploaded images + */ +?> +<div class="contentWrapper"> +<form action="<?php echo $vars['url']; ?>action/tidypics/edit_multi" method="post"> +<?php + + $file_array = $vars['file_array']; + + // make sure one of the images becomes the cover if there isn't one already + $album_entity = get_entity($vars['album_guid']); + if (!$album_entity->cover) $no_cover = true; + + foreach ($file_array as $key => $file_guid){ + $entity = get_entity($file_guid); + $guid = $entity->guid; + $body = $entity->description; + $title = $entity->title; + $tags = $entity->tags; + $container_guid = $entity->container_guid; + + // first one is default cover if there isn't one already + if ($no_cover) { + $val = $guid; + $no_cover = false; + } + + echo '<div class="tidypics_edit_image_container">'; + echo '<img src="' . $vars['url'] . 'mod/tidypics/thumbnail.php?file_guid=' . $guid . '&size=small" class="tidypics_edit_images" alt="' . $title . '"/>'; + echo '<div class="tidypics_image_info">'; + echo '<p><label>' . elgg_echo('album:title') . '</label>'; + echo elgg_view("input/text", array("internalname" => "title[$key]", "value" => $title,)) . "\n"; + echo '</p>'; + echo '<p><label>' . elgg_echo('caption') . "</label>"; + echo elgg_view("input/longtext",array("internalname" => "caption[$key]", "value" => $body, "class" => 'tidypics_caption_input',)) . "\n"; + echo "</p>"; + echo '<p><label>' . elgg_echo("tags") . "</label>\n"; + echo elgg_view("input/tags", array( "internalname" => "tags[$key]","value" => $tags)) . "\n"; + echo '</p>'; + echo '<input type="hidden" name="image_guid[' .$key. ']" value="'. $guid .'">' . "\n"; + echo elgg_view('input/securitytoken'); + + echo elgg_view("input/radio", array("internalname" => "cover", + "value" => $val, + 'options' => array( elgg_echo('album:cover') => $guid, + ), + )); + echo '</div>'; + echo '</div>'; + } + +?> +<input type="hidden" name="container_guid" value="<?php echo $container_guid; ?>" /> +<p><input type="submit" name="submit" value="<?php echo elgg_echo('save'); ?>" /></p> +</form> +</div> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/forms/settings.php b/plugins/tidypics/views/default/tidypics/forms/settings.php new file mode 100644 index 0000000000000000000000000000000000000000..0729b536b4cbbc9e02f23c42e2de5c9591e568b8 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/forms/settings.php @@ -0,0 +1,158 @@ +<?php + /** + * Tidypics admin settings form + */ + + + + $action = $vars['url'] . 'action/tidypics/settings'; + + $plugin = find_plugin_settings('tidypics'); + + + // bootstrap the plugin version here for now + if (!$plugin->version) { + set_plugin_setting('version', 1.62, 'tidypics'); + } + + + // Main settings + $form_body = '<h3>' . elgg_echo('tidypics:settings:heading:main') . '</h3>'; + + // Tagging + $tagging = $plugin->tagging; + if(!$tagging) $tagging = "enabled"; + $form_body .= '<p class="admin_debug">' . elgg_view("input/checkboxes", array('options' => array(elgg_echo('tidypics:settings:tagging') => 'enabled'), 'internalname' => 'tagging', 'value' => $tagging )) . "</p>"; + + // Download Link + $download_link = $plugin->download_link; + if(!$download_link) $download_link = "enabled"; + $form_body .= '<p class="admin_debug">' . elgg_view("input/checkboxes", array('options' => array(elgg_echo('tidypics:settings:download_link') => 'enabled'), 'internalname' => 'download_link', 'value' => $download_link )) . "</p>"; + + // Ratings + $photo_ratings = $plugin->photo_ratings; + if(!$photo_ratings) $photo_ratings = "disabled"; + $form_body .= '<p class="admin_debug">' . elgg_view("input/checkboxes", array('options' => array(elgg_echo('tidypics:settings:photo_ratings') => 'enabled'), 'internalname' => 'photo_ratings', 'value' => $photo_ratings )) . "</p>"; + + // Show EXIF + $exif = $plugin->exif; + if(!$exif) $exif = "disabled"; + $form_body .= '<p class="admin_debug">' . elgg_view("input/checkboxes", array('options' => array(elgg_echo('tidypics:settings:exif') => 'enabled'), 'internalname' => 'exif', 'value' => $exif )) . "</p>"; + + // Show View count + $view_count = $plugin->view_count; + if(!$view_count) $view_count = "enabled"; + $form_body .= '<p class="admin_debug">' . elgg_view("input/checkboxes", array('options' => array(elgg_echo('tidypics:settings:view_count') => 'enabled'), 'internalname' => 'view_count', 'value' => $view_count )) . "</p>"; + + // Watermark Text + $form_body .= "<p>" . elgg_echo('tidypics:settings:watermark') . "<br />"; + $form_body .= elgg_view("input/text",array('internalname' => 'params[watermark_text]', 'value' => $plugin->watermark_text)) . "</p>"; + + // Max Image Size + $maxfilesize = $plugin->maxfilesize; + if (!$maxfilesize) $maxfilesize = (int)5; // 5 MB + $form_body .= "<p>" . elgg_echo('tidypics:settings:maxfilesize') . "<br />"; + $form_body .= elgg_view("input/text",array('internalname' => 'params[maxfilesize]', 'value' => $maxfilesize)) . "</p>"; + + // Quota Size + $quota = $plugin->quota; + if (!$quota) $quota = 0; + $form_body .= "<p>" . elgg_echo('tidypics:settings:quota') . "<br />"; + $form_body .= elgg_view("input/text",array('internalname' => 'params[quota]', 'value' => $quota)) . "</p>"; + + // Image Library + if (extension_loaded('imagick')) { + $img_lib_options['ImageMagickPHP'] = 'imagick PHP extension'; + } + + $disablefunc = explode(',', ini_get('disable_functions')); + if (is_callable('exec') && !in_array('exec',$disablefunc)) { + $img_lib_options['ImageMagick'] = 'ImageMagick Cmdline'; + } + + $img_lib_options['GD'] = 'GD'; + + $form_body .= '<h3>' . elgg_echo('tidypics:settings:heading:img_lib') . '</h3>'; + $image_lib = $plugin->image_lib; + if (!$image_lib) $image_lib = 'GD'; + $form_body .= '<p>' . elgg_echo('tidypics:settings:image_lib') . ': '; + $form_body .= elgg_view('input/pulldown', array( + 'internalname' => 'params[image_lib]', + 'options_values' => $img_lib_options, + 'value' => $image_lib + )); + $form_body .= '<br/>Note: If you want to select ImageMagick Command Line, first confirm that it is installed on your server.</p>'; + + if (is_callable('exec') && !in_array('exec',$disablefunc)) { + // Image Magick Path + $im_path = $plugin->im_path; + if(!$im_path) $im_path = "/usr/bin/"; + $form_body .= "<p>" . elgg_echo('tidypics:settings:im_path') . "<br />"; + $form_body .= elgg_view("input/text",array('internalname' => 'params[im_path]', 'value' => $im_path)) . "</p>"; + } + + + // River Image options + $form_body .= '<h3>' . elgg_echo('tidypics:settings:heading:river') . '</h3>'; + $img_river_view = $plugin->img_river_view; + if (!$img_river_view) $img_river_view = '1'; + $form_body .= '<p>' . elgg_echo('tidypics:settings:img_river_view'); + $form_body .= elgg_view('input/pulldown', array( + 'internalname' => 'params[img_river_view]', + 'options_values' => array( + 'all' => 'all', + '1' => '1', + 'none' => 'none', + ), + 'value' => $img_river_view + )); + $form_body .= '</p>'; + + // River Album options + $album_river_view = $plugin->album_river_view; + if (!$album_river_view) $album_river_view = 'set'; + $form_body .= '<p>' . elgg_echo('tidypics:settings:album_river_view'); + $form_body .= elgg_view('input/pulldown', array( + 'internalname' => 'params[album_river_view]', + 'options_values' => array( + 'cover' => 'cover', + 'set' => 'set', + ), + 'value' => $album_river_view + )); + $form_body .= '</p>'; + + // Thumbnail sizes + $form_body .= '<h3>' . elgg_echo('tidypics:settings:heading:sizes') . '</h3>'; + $form_body .= "<h6>You must edit the css if you change the default sizes</h6>"; + $image_sizes = $plugin->image_sizes; + if(!$image_sizes) { + $image_sizes = array(); // set default values + $image_sizes['large_image_width'] = $image_sizes['large_image_height'] = 600; + $image_sizes['small_image_width'] = $image_sizes['small_image_height'] = 153; + $image_sizes['thumb_image_width'] = $image_sizes['thumb_image_height'] = 60; + } else { + $image_sizes = unserialize($image_sizes); + } + $form_body .= "<p>" . elgg_echo('tidypics:settings:largesize') . "<br />"; + $form_body .= 'width: <input style="width: 20%;" type="text" name="large_thumb_width" value=' . "\"{$image_sizes['large_image_width']}\"" . ' class="input-text" /> '; + $form_body .= 'height: <input style="width: 20%;" type="text" name="large_thumb_height" value=' . "\"{$image_sizes['large_image_height']}\"" . ' class="input-text" /></p>'; + + $form_body .= "<p>" . elgg_echo('tidypics:settings:smallsize') . "<br />"; + $form_body .= 'width and height: <input style="width: 20%;" type="text" name="small_thumb_width" value=' . "\"{$image_sizes['small_image_width']}\"" . ' class="input-text" /> '; + //$form_body .= 'height: <input style="width: 20%;" type="text" name="small_thumb_height" value=' . "\"{$image_sizes['small_image_height']}\"" . ' class="input-text" /></p>'; + + $form_body .= "<p>" . elgg_echo('tidypics:settings:thumbsize') . "<br />"; + $form_body .= 'width and height: <input style="width: 20%;" type="text" name="thumb_width" value=' . "\"{$image_sizes['thumb_image_width']}\"" . ' class="input-text" /> '; + //$form_body .= 'height: <input style="width: 20%;" type="text" name="thumb_height" value=' . "\"{$image_sizes['thumb_image_height']}\"" . ' class="input-text" /></p>'; + + + // Group permission override + $form_body .= '<h3>' . elgg_echo('tidypics:settings:heading:groups') . '</h3>'; + $grp_perm_override = $plugin->grp_perm_override; + if(!$grp_perm_override) $grp_perm_override = "enabled"; + $form_body .= '<p class="admin_debug">' . elgg_view("input/checkboxes", array('options' => array(elgg_echo('tidypics:settings:grp_perm_override') => 'enabled'), 'internalname' => 'grp_perm_override', 'value' => $grp_perm_override )) . "</p>"; + + $form_body .= elgg_view('input/submit', array('value' => elgg_echo("save"))); + + echo elgg_view('input/form', array('action' => $action, 'body' => $form_body)); diff --git a/plugins/tidypics/views/default/tidypics/forms/setupFlickr.php b/plugins/tidypics/views/default/tidypics/forms/setupFlickr.php new file mode 100644 index 0000000000000000000000000000000000000000..8c31d0883bcb65af3f63a9d6c22c9330a6a7934b --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/forms/setupFlickr.php @@ -0,0 +1,42 @@ +<?php +require_once( dirname(dirname(dirname(dirname(dirname(__FILE__)))))) . "/lib/flickr.php"; + +$user = get_loggedin_user(); +$flickr_username = get_metadata_byname( $user->guid, "flickr_username" ); +$flickr_album_id = get_metadata_byname( $user->guid, "flickr_album_id" ); + +$action = $vars['url'] . 'action/tidypics/flickrSetup'; + +$form_body = "<p>". elgg_echo( 'flickr:intro' ) . "</p><p>"; +$form_body .= elgg_echo( 'flickr:usernamesetup') . " <input style='width: 20%;' type='text' name='flickr_username' value='$flickr_username->value' ' class='input-text' /> <br />"; +$form_body .= "<input type='hidden' name='return_url' value='$_SERVER[REQUEST_URI]' />"; + +$albums = get_entities( "object", "album", $user->guid ); +$options = array( 0 => elgg_echo( 'flickr:selectalbum' )); +foreach( $albums as $album ) { + $title = $album->title; + switch( $album->access_id ) { + case ACCESS_PRIVATE: + $title .= " (" . elgg_echo( 'private' ) . ")"; + break; + case ACCESS_PUBLIC: + $title .= " (" . elgg_echo( 'public' ) . ")"; + break; + default: + $title .= " (no known permission set)"; + break; + } + $options[$album->guid] = $title; +} + +$form_body .= "<br />" . elgg_echo( 'flickr:albumdesc' ); +$form_body .= elgg_view('input/pulldown', array('internalname' => 'album_id', + 'options_values' => $options, + 'value' => $flickr_album_id->value )); +$form_body .= "<br />"; +$form_body .= elgg_view('input/submit', array('value' => elgg_echo("save"))); + +flickr_menu(); + +echo elgg_view('input/form', array('action' => $action, 'body' => $form_body)); +?> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/forms/upload.php b/plugins/tidypics/views/default/tidypics/forms/upload.php new file mode 100644 index 0000000000000000000000000000000000000000..6e755612c25057eb993c47f89c9e041447a04757 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/forms/upload.php @@ -0,0 +1,99 @@ +<?php + global $CONFIG; + + //this is for image uploads only. Image edits are handled by edit.php form + + $container_guid = get_input('container_guid'); + $album = get_entity($vars['album']); + $access_id = $album->access_id; + + $maxfilesize = (float) get_plugin_setting('maxfilesize','tidypics'); + if (!$maxfilesize) + $maxfilesize = 5; + + $quota = get_plugin_setting('quota','tidypics'); + if ($quota) { + $image_repo_size_md = get_metadata_byname($album->container_guid, "image_repo_size"); + $image_repo_size = (int)$image_repo_size_md->value; + $image_repo_size = $image_repo_size / 1024 / 1024; + $quote_percentage = round(100 * ($image_repo_size / $quota)); + // for small quotas, so one decimal place + if ($quota < 10) { + $image_repo_size = sprintf('%.1f', $image_repo_size); + } else { + $image_repo_size = round($image_repo_size); + } + if ($image_repo_size > $quota) { + $image_repo_size = $quota; + } + } + +?> +<div id="tidypics_ref"></div> +<div class="contentWrapper"> +<?php + ob_start(); +?> +<p style="line-height:1.6em;"> + <label><?php echo elgg_echo("images:upload"); ?></label><br /> + <i><?php echo elgg_echo("tidypics:settings:maxfilesize") . ' ' . $maxfilesize; ?></i><br /> +<?php + if ($quota) { +?> + <i><?php echo elgg_echo("tidypics:quota") . ' ' . $image_repo_size . '/' . $quota . " MB ({$quote_percentage}%)"; ?></i><br /> +<?php + } +?> + <div class="tidypics_popup"> + <?php echo elgg_echo("tidypics:uploading:images"); ?><br /> + <div style="margin:20px 0px 20px 80px;"><img id="progress" alt="..." border="0" src="<?php echo $vars['url'].'mod/tidypics/graphics/loader.gif' ?>" /></div> + </div> + <ol id="tidypics_image_upload_list"> +<?php + for ($x = 0; $x < 10; $x++) { + echo '<li>' . elgg_view("input/file",array('internalname' => "upload_$x")) . '</li>'; + } +?> + </ol> +</p> +<p> +<?php + if ($container_guid) + echo '<input type="hidden" name="container_guid" value="' . $container_guid . '" />'; + if ($access_id) + echo '<input type="hidden" name="access_id" value="' . $access_id . '" />'; +?> + <input type="submit" value="<?php echo elgg_echo("save"); ?>" onclick="displayProgress();" /> +</p> +<?php + $form_body = ob_get_clean(); + + echo elgg_view('input/form', array( 'action' => "{$vars['url']}action/tidypics/upload", + 'body' => $form_body, + 'internalid' => 'tidypicsUpload', + 'enctype' => 'multipart/form-data', + 'method' => 'post',)); +?> +</div> +<script type="text/javascript"> + + function displayProgress() + { + offsetY = 60; + offsetX = 120; + + divWidth = $('#tidypics_ref').width(); + imgOffset = $('#tidypics_ref').offset(); + imgWidth = $('#tidypics_ref').width(); + + _top = imgOffset.top + offsetY; + _left = imgOffset.left + offsetX; + + $('.tidypics_popup').show().css({ + "top": _top + "px", + "left": _left + "px" + }); + + setTimeout('document.images["progress"].src = "<?php echo $vars['url'].'mod/tidypics/graphics/loader.gif' ?>"', 200); + } +</script> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/gallery.php b/plugins/tidypics/views/default/tidypics/gallery.php new file mode 100644 index 0000000000000000000000000000000000000000..74aa34500bb3ba1085841e56cd23c0d8076c8ee1 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/gallery.php @@ -0,0 +1,67 @@ +<?php +/** + * view a gallery of photos or albums + * + */ + +// four albums across +$num_wide = 4; + +$context = $vars['context']; +$offset = $vars['offset']; +$entities = $vars['entities']; +$limit = $vars['limit']; +$count = $vars['count']; +$baseurl = $vars['baseurl']; +$context = $vars['context']; +$viewtype = $vars['viewtype']; +$pagination = $vars['pagination']; +$fullview = $vars['fullview']; + +$html = ""; +$nav = ""; + +if (isset($vars['viewtypetoggle'])) { + $viewtypetoggle = $vars['viewtypetoggle']; +} else { + $viewtypetoggle = true; +} + +if ($context == "search" && $count > 0 && $viewtypetoggle) { + $nav .= elgg_view('navigation/viewtype', array( + 'baseurl' => $baseurl, + 'offset' => $offset, + 'count' => $count, + 'viewtype' => $viewtype, + )); +} + +if ($pagination) { + $nav .= elgg_view('navigation/pagination',array( + 'baseurl' => $baseurl, + 'offset' => $offset, + 'count' => $count, + 'limit' => $limit, + )); +} + +$html .= $nav; + +if (is_array($entities) && sizeof($entities) > 0) { + $counter = 0; + foreach($entities as $entity) { + if ($counter % $num_wide == 0) { + $html .= "<div class=\"tidypics_line_break\"></div>"; + } + $html .= elgg_view_entity($entity, $fullview); + $counter++; + } +} + +$html .= '<div class="clearfloat"></div>'; + +if ($count) { + $html .= $nav; +} + +echo $html; \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/groupprofile_albums.php b/plugins/tidypics/views/default/tidypics/groupprofile_albums.php new file mode 100644 index 0000000000000000000000000000000000000000..7cb89bf1c0fa73b74ccbcca23f98dacfb8496410 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/groupprofile_albums.php @@ -0,0 +1,18 @@ +<?php + +/*********************************************** + * + * This is used on the group profile page + * + ***********************************************/ + +if ($vars['entity']->photos_enable != 'no') { + echo '<div id="tidypics_group_profile">'; +?> + <h2><a href="<?php echo $CONFIG->wwwroot . "pg/photos/owned/group:" . $vars['entity']->guid; ?>">Group albums</a></h2> +<?php + //echo '<h2>' . elgg_echo('album:group') . '</h2>'; + echo elgg_view('tidypics/albums', array('num_albums' => 5)); + echo '</div>'; +} +?> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/hover_menu.php b/plugins/tidypics/views/default/tidypics/hover_menu.php new file mode 100644 index 0000000000000000000000000000000000000000..240891f5112fa8691d8ccd46d145ef1053b0f17d --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/hover_menu.php @@ -0,0 +1,12 @@ +<?php + + /** + * Elgg hoverover extender for tidypics + * + */ + +?> + + <p class="user_menu_file <?php if(get_context() == 'photos') echo 'profile_select';?>"> + <a href="<?php echo $vars['url']; ?>pg/photos/owned/<?php echo $vars['entity']->username; ?>"><?php echo elgg_echo("albums"); ?></a> + </p> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/image_menu.php b/plugins/tidypics/views/default/tidypics/image_menu.php new file mode 100644 index 0000000000000000000000000000000000000000..498cfe724c6c1a778dbb443f378a8cde6052d132 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/image_menu.php @@ -0,0 +1,51 @@ +<?php + + /************************************************************************** + * + * Tidypics Image Menu + * + * This is the menu that appears below an image. Admins can override the + * menu with a different view to provide a look and feel that matches + * their themes. The view can be extended to provide additional controls. + * + **************************************************************************/ + + $image_guid = $vars['image_guid']; + $viewer = $vars['viewer']; + $owner = $vars['owner']; + $anytags = $vars['anytags']; + $album = $vars['album']; + + if (get_plugin_setting('tagging', 'tidypics') != "disabled") { + + $can_tag = false; + + $container = get_entity($album->container_guid); + if ($container instanceof ElggGroup) { + $can_tag = $viewer && $container->isMember($viewer); + } else { + $can_tag = $viewer && $viewer->guid == $owner->guid || user_is_friend($owner->guid, $viewer->guid); + } + + // only owner and friends of owner can tag + if ($can_tag) { +?> +<li id="start_tagging"><a id="tidypics_tag_control" href="javascript:void(0)" onclick="startTagging()"><?php echo elgg_echo('tidypics:tagthisphoto'); ?></a></li> +<?php + } + + // only owner can delete tags + if ($anytags && $viewer && $viewer->guid == $owner->guid) { +?> +<li id="delete_tags"><a href="javascript:void(0)" onclick="deleteTags()"><?php echo elgg_echo('tidypics:deletetag'); ?></a></li> +<?php + } + } + + if (get_plugin_setting('download_link', 'tidypics') != "disabled") { + $download_url = $vars['url'] . "pg/photos/download/{$image_guid}/"; +?> +<li id="download_image"><a href="<?php echo $download_url; ?>"><?php echo elgg_echo("image:download"); ?></a></li> +<?php + } +?> \ No newline at end of file diff --git a/plugins/tidypics/views/default/tidypics/js/slideshow.php b/plugins/tidypics/views/default/tidypics/js/slideshow.php new file mode 100644 index 0000000000000000000000000000000000000000..d134ca809b1ee00f79f98da81db858b2961857c8 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/js/slideshow.php @@ -0,0 +1,2 @@ + +<script type="text/javascript" src="<?php echo $vars['url']; ?>mod/tidypics/vendors/PicLensLite/piclens_optimized.js"></script> diff --git a/plugins/tidypics/views/default/tidypics/js/tagging.php b/plugins/tidypics/views/default/tidypics/js/tagging.php new file mode 100644 index 0000000000000000000000000000000000000000..3ffa20cfba24e4f3fc8221f9e52d431b68f55e13 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/js/tagging.php @@ -0,0 +1,304 @@ +<?php + $photo_tags_json = $vars['photo_tags_json']; +?> + +<script type="text/javascript" src="<?php echo $vars['url'] ?>mod/tidypics/vendors/jquery.imgareaselect-0.7.js"></script> +<script type="text/javascript" src="<?php echo $vars['url'] ?>mod/tidypics/vendors/jquery.quicksearch.js"></script> + +<script type="text/javascript"> + + var coordinates = ""; + var user_id = 0; + var tagging = 0; + + // add to DOM as soon as ready + $(document).ready(function () { + $('ul#tidypics_phototag_list li').quicksearch({ + position: 'before', + attached: 'ul#tidypics_phototag_list', + loaderText: '', + inputClass: 'input-filter', + delay: 100 + }); + + $('#quicksearch').submit( function () { addTag() } ); + } + ); + + // images are loaded so process tags + $(window).load(function () { + $('#tidypics_image').setupTags(); + } + ); + + // get tags over image ready for mouseover + // based on code by Tarique Sani tarique at sanisoft.com - MIT and GPL licenses + $.fn.setupTags = function() + { + + image = this; + + imgOffset = $(image).offset(); + imgOffset.left = parseInt(imgOffset.left) + parseInt($(image).css("border-left-width")) + parseInt($(image).css("padding-left")); + imgOffset.top = parseInt(imgOffset.top) + parseInt($(image).css("border-top-width")) + parseInt($(image).css("padding-top")); + + tags = <?php echo $photo_tags_json; ?>; + + $(tags).each(function(){ + appendTag(imgOffset, this); + }); + + $(image).hover( + function(){ + $('.tidypics_tag').show(); + }, + function(){ + $('.tidypics_tag').hide(); + } + ); + + addTagEvents(); + + $('.tidypics_phototag_links').hover( + function(){ + code = this.id.substr(7); // cut off taglink to get unique id + $('#tag'+code).show(); + }, + function(){ + code = this.id.substr(7); + $('#tag'+code).hide(); + } + ); + + // make sure we catch and handle when the browser is resized + $(window).resize(function () { + $('.tidypics_tag').remove(); + + imgOffset = $(image).offset(); + + $(tags).each(function(){ + appendTag(imgOffset, this); + }); + + addTagEvents(); + }); + } + + function appendTag(offset, tag) + { + // catch for IE when no tags available + if (tag.id == undefined) + return; + + tag_top = parseInt(imgOffset.top) + parseInt(tag.y1); + tag_left = parseInt(imgOffset.left) + parseInt(tag.x1); + + tag_div = $('<div class="tidypics_tag" id="tag'+tag.id+'"></div>').css({ left: tag_left + 'px', top: tag_top + 'px', width: tag.width + 'px', height: tag.height + 'px' }); + + text_top = parseInt(tag_top) + parseInt(tag.height) + 5; + + tag_text_div = $('<div class="tidypics_tag_text">'+tag.text+'</div>').css({ left: tag_left + 'px', top: text_top + 'px', width: '120px'}); + + $('body').append(tag_div); + $('body').append(tag_text_div); + } + + function addTagEvents() + { + $('.tidypics_tag').hover( + function(){ + $('.tidypics_tag').show(); + $(this).next('.tidypics_tag_text').show(); + $(this).next('.tidypics_tag_text').css("z-index", 10000); + }, + function(){ + $('.tidypics_tag').show(); + $(this).next('.tidypics_tag_text').hide(); + $(this).next('.tidypics_tag_text').css("z-index", 0); + } + ); + } + + + function selectUser(id, name) + { + user_id = id; + $("input.input-filter").val(name); + } + + function startTagging() + { + if (tagging != 0) + { + stopTagging(); + return; + } + + tagging = 1; + + $('#tidypics_tag_control').text("<?php echo elgg_echo('tidypics:finish_tagging'); ?>"); + + showTagInstruct(); + $('#tidypics_delete_tag_menu').hide(); + + $('#tidypics_image').hover( + function(){ + $('.tidypics_tag').hide(); + }, + function(){ + $('.tidypics_tag').hide(); + } + ); + + $('img#tidypics_image').imgAreaSelect( { + borderWidth: 2, + borderColor1: 'white', + borderColor2: 'white', + disable: false, + hide: false, + onSelectEnd: showTagMenu, + onSelectStart: hideTagMenu + } + ); + + $('img#tidypics_image').css({"cursor" : "crosshair"}); + } + + function stopTagging() + { + tagging = 0; + + hideTagInstruct(); + hideTagMenu(); + + $('img#tidypics_image').imgAreaSelect( {hide: true, disable: true} ); + + $('#tidypics_tag_control').text("<?php echo elgg_echo('tidypics:tagthisphoto'); ?>"); + + // restart tag hovering + $('#tidypics_image').hover( + function(){ + $('.tidypics_tag').show(); + }, + function(){ + $('.tidypics_tag').hide(); + } + ); + + $('img#tidypics_image').css({"cursor" : "pointer"}); + } + + function showTagMenu(oObject, oCoordenates) + { + offsetX = 6; + offsetY = 10; + + imgOffset = $('#tidypics_image').offset(); + + // show the list of friends + if (oCoordenates.width != 0 && oCoordenates.height != 0) { + coordinates = oCoordenates; + + _top = imgOffset.top + oCoordenates.y2 + offsetY; + _left = imgOffset.left + oCoordenates.x1 + offsetX; + + $('#tidypics_tag_menu').show().css({ + "top": _top + "px", + "left": _left + "px" + }); + + $(".input-filter").focus(); + } + } + + + function hideTagMenu() + { + $('#tidypics_tag_menu').hide(); + } + + function showTagInstruct() + { + offsetY = -60; + + divWidth = $('#tidypics_tag_instructions').width(); + imgOffset = $('#tidypics_image').offset(); + imgWidth = $('#tidypics_image').width(); + offsetX = parseInt((imgWidth - divWidth)/2); + + _top = imgOffset.top + offsetY; + _left = imgOffset.left + offsetX; + + $('#tidypics_tag_instructions').show().css({ + "top": _top + "px", + "left": _left + "px" + }); + } + + function hideTagInstruct() + { + $('#tidypics_tag_instructions').hide(); + } + + function addTag() + { + // do I need a catch for no tag? + + $("input#user_id").val(user_id); + $("input#word").val( $("input.input-filter").val() ); + + coord_string = '"x1":"' + coordinates.x1 + '",'; + coord_string += '"y1":"' + coordinates.y1 + '",'; + coord_string += '"width":"' + coordinates.width + '",'; + coord_string += '"height":"' + coordinates.height + '"'; + + $("input#coordinates").val(coord_string); + + //Show loading + //$("#tag_menu").replaceWith('<div align="center" class="ajax_loader"></div>'); + } + + function deleteTags() + { + offsetY = 60; + + stopTagging(); + + divWidth = $('#delete_tag_menu').width(); + imgOffset = $('#tidypics_image').offset(); + imgWidth = $('#tidypics_image').width(); + offsetX = parseInt((imgWidth - divWidth)/2); + + _top = imgOffset.top + offsetY; + _left = imgOffset.left + offsetX; + + $('#tidypics_delete_tag_menu').show().css({ + "top": _top + "px", + "left": _left + "px" + }); + + $('#tidypics_image').hover( + function(){ + $('.tidypics_tag').hide(); + }, + function(){ + $('.tidypics_tag').hide(); + } + ); + } + + function hideDeleteMenu() + { + $('#tidypics_delete_tag_menu').hide(); + + // restart tag hovering + $('#tidypics_image').hover( + function(){ + $('.tidypics_tag').show(); + }, + function(){ + $('.tidypics_tag').hide(); + } + ); + } +</script> diff --git a/plugins/tidypics/views/default/tidypics/tagging.php b/plugins/tidypics/views/default/tidypics/tagging.php new file mode 100644 index 0000000000000000000000000000000000000000..251534b80f5903b3b930671f6395f86d83c271e3 --- /dev/null +++ b/plugins/tidypics/views/default/tidypics/tagging.php @@ -0,0 +1,89 @@ +<?php + + $image = $vars['image']; + $viewer = $vars['viewer']; + $owner = $vars['owner']; + + // get photo tags + $tag_info = $image->getPhotoTags(); + + // defining json text as "" makes sure the tagging javascript code doesn't throw errors if no tags + $photo_tags_json = "\"\""; + if ($tag_info) { + $photo_tags_json = $tag_info['json']; + } + + if ($tag_info) { +?> +<div id="tidypics_phototags_list"> + <h3><?php echo elgg_echo('tidypics:inthisphoto') ?></h3> + <ul> +<?php + foreach ($tag_info['links'] as $id=>$link) { + echo "<li><a class='tidypics_phototag_links' id='taglink{$id}' href='{$link['url']}'>{$link['text']}</a></li>"; + } +?> + </ul> +</div> +<?php + } +?> +<div id='tidypics_tag_instructions'> + <div id='tidypics_tag_instruct_text'><?php echo elgg_echo('tidypics:taginstruct'); ?></div> + <div id='tidypics_tag_instruct_button_div'><button class='submit_button' id='tidypics_tag_instruct_button' onclick='stopTagging()'><?php echo elgg_echo('tidypics:finish_tagging'); ?></button></div> +</div> +<div id="tidypics_tag_menu" class="tidypics_popup"> + <div class='tidypics_popup_header'><h3><?php echo elgg_echo('tidypics:tagthisphoto'); ?></h3></div> +<?php + + if ($viewer) { + + $people_list = tp_get_tag_list($viewer); + + $content = "<div id='tidypics_tagmenu_left'>"; + $content .= "<input type='hidden' name='image_guid' value='{$image->guid}' />"; + $content .= "<input type='hidden' name='coordinates' id='coordinates' value='' />"; + $content .= "<input type='hidden' name='user_id' id='user_id' value='' />"; + $content .= "<input type='hidden' name='word' id='word' value='' />"; + + $content .= "<ul id='tidypics_phototag_list'>"; + $content .= "<li><a href='javascript:void(0)' onclick='selectUser({$viewer->getGUID()},\"{$viewer->name}\")'> {$viewer->name} (" . elgg_echo('me') . ")</a></li>"; + + if ($people_list) { + foreach($people_list as $friend_guid => $friend_name) { + $content .= "<li><a href='javascript:void(0)' onclick='selectUser({$friend_guid}, \"{$friend_name}\")'>{$friend_name}</a></li>"; + } + } + + $content .= "</ul></div>"; + + $content .= "<div id='tidypics_tagmenu_right'><input type='submit' value='" . elgg_echo('tidypics:actiontag') . "' class='submit_button' /></div>"; + + echo elgg_view('input/form', array('internalid' => 'quicksearch', 'internalname' => 'tidypics_phototag_form', 'class' => 'quicksearch', 'action' => "{$vars['url']}action/tidypics/addtag", 'method' => 'post', 'body' => $content)); + } + +?> +<div class="clearfloat"></div> +</div> +<div id="tidypics_delete_tag_menu" class="tidypics_popup"> + <div class='tidypics_popup_header'><h3><?php echo elgg_echo('tidypics:deltag_title'); ?></h3></div> + +<?php + if ($tag_info) { + $content = "<input type='hidden' name='image_guid' value='{$image->guid}' />"; + foreach ($tag_info['links'] as $id => $link) { + $text = htmlentities($link['text'], ENT_QUOTES, 'UTF-8'); + $content .= "<label><input type=\"checkbox\" class=\"input-checkboxes\" name=\"tags[{$id}]\" value=\"{$text}\" />{$text}</label><br />"; + } + + $content .= "<input type='submit' value='" . elgg_echo('tidypics:actiondelete') . "' class='submit_button' />"; + $content .= "<input type='button' value='" . elgg_echo('cancel') . "' class='cancel_button' onclick='hideDeleteMenu();' />"; + + echo elgg_view('input/form', array('internalname' => 'phototag_deletetag_form', 'action' => "{$vars['url']}action/tidypics/deletetag", 'method' => 'post', 'body' => $content)); + + } +?> +</div> +<?php + echo elgg_view('tidypics/js/tagging', array('photo_tags_json' => $photo_tags_json,) ); +?> \ No newline at end of file diff --git a/plugins/tidypics/views/default/widgets/album_view/edit.php b/plugins/tidypics/views/default/widgets/album_view/edit.php new file mode 100644 index 0000000000000000000000000000000000000000..992699cb06b45246fae8b1ae1885e2968ad59997 --- /dev/null +++ b/plugins/tidypics/views/default/widgets/album_view/edit.php @@ -0,0 +1,24 @@ +<p> +<?php + + echo elgg_echo("tidypics:widget:num_albums") . ": "; + + + if($vars['entity']->num_display == '') $vars['entity']->num_display = 5; + +?> + <select name="params[num_display]"> + <option value="1" <?php if($vars['entity']->num_display == 1) echo "SELECTED"; ?>>1</option> + <option value="2" <?php if($vars['entity']->num_display == 2) echo "SELECTED"; ?>>2</option> + <option value="3" <?php if($vars['entity']->num_display == 3) echo "SELECTED"; ?>>3</option> + <option value="4" <?php if($vars['entity']->num_display == 4) echo "SELECTED"; ?>>4</option> + <option value="5" <?php if($vars['entity']->num_display == 5) echo "SELECTED"; ?>>5</option> + <option value="6" <?php if($vars['entity']->num_display == 6) echo "SELECTED"; ?>>6</option> + <option value="7" <?php if($vars['entity']->num_display == 7) echo "SELECTED"; ?>>7</option> + <option value="8" <?php if($vars['entity']->num_display == 8) echo "SELECTED"; ?>>8</option> + <option value="9" <?php if($vars['entity']->num_display == 9) echo "SELECTED"; ?>>9</option> + <option value="10" <?php if($vars['entity']->num_display == 10) echo "SELECTED"; ?>>10</option> + <option value="15" <?php if($vars['entity']->num_display == 15) echo "SELECTED"; ?>>15</option> + <option value="20" <?php if($vars['entity']->num_display == 20) echo "SELECTED"; ?>>20</option> + </select> +</p> \ No newline at end of file diff --git a/plugins/tidypics/views/default/widgets/album_view/view.php b/plugins/tidypics/views/default/widgets/album_view/view.php new file mode 100644 index 0000000000000000000000000000000000000000..b4248df35fae3e427b840b62754934e489aa265a --- /dev/null +++ b/plugins/tidypics/views/default/widgets/album_view/view.php @@ -0,0 +1,13 @@ +<div class="contentWrapper"> +<?php + + //the number of files to display + $number = (int) $vars['entity']->num_display; + //if no number has been set, default to 5 + if (!$number) + $number = 5; + + echo elgg_view('tidypics/albums', array('num_albums' => $number)); + +?> +</div> \ No newline at end of file diff --git a/plugins/tidypics/views/default/widgets/latest_photos/edit.php b/plugins/tidypics/views/default/widgets/latest_photos/edit.php new file mode 100644 index 0000000000000000000000000000000000000000..3b334d722e7116c36473baa69256aeaba13b71c7 --- /dev/null +++ b/plugins/tidypics/views/default/widgets/latest_photos/edit.php @@ -0,0 +1,15 @@ +<p> +<?php + echo elgg_echo("tidypics:widget:num_latest") . ": "; + + if($vars['entity']->num_display == '') $vars['entity']->num_display = 6; + +?> + <select name="params[num_display]"> + <option value="6" <?php if($vars['entity']->num_display == 6) echo "SELECTED"; ?>>6</option> + <option value="9" <?php if($vars['entity']->num_display == 9) echo "SELECTED"; ?>>9</option> + <option value="12" <?php if($vars['entity']->num_display == 12) echo "SELECTED"; ?>>12</option> + <option value="15" <?php if($vars['entity']->num_display == 15) echo "SELECTED"; ?>>15</option> + <option value="18" <?php if($vars['entity']->num_display == 18) echo "SELECTED"; ?>>18</option> + </select> +</p> \ No newline at end of file diff --git a/plugins/tidypics/views/default/widgets/latest_photos/view.php b/plugins/tidypics/views/default/widgets/latest_photos/view.php new file mode 100644 index 0000000000000000000000000000000000000000..0c319390714a01ab29b35679fcb7ebb2a5adae17 --- /dev/null +++ b/plugins/tidypics/views/default/widgets/latest_photos/view.php @@ -0,0 +1,15 @@ +<div class="contentWrapper"> +<?php + + //the number of files to display + $number = (int) $vars['entity']->num_display; + //if no number has been set, default to 6 + if (!$number) + $number = 6; + + echo '<div class="tidypics_widget_latest">'; + echo tp_get_latest_photos($number, page_owner()); + echo '</div>'; + +?> +</div> \ No newline at end of file diff --git a/plugins/tidypics/views/rss/extensions/tidypics/channel.php b/plugins/tidypics/views/rss/extensions/tidypics/channel.php new file mode 100644 index 0000000000000000000000000000000000000000..8b620d15dd713f39dc0d8b58ac005b3e8b505248 --- /dev/null +++ b/plugins/tidypics/views/rss/extensions/tidypics/channel.php @@ -0,0 +1 @@ +<description /> \ No newline at end of file diff --git a/plugins/tidypics/views/rss/extensions/tidypics/xmlns.php b/plugins/tidypics/views/rss/extensions/tidypics/xmlns.php new file mode 100644 index 0000000000000000000000000000000000000000..cb9646dcbe3ae54269d310a5bad9863b6693b7e7 --- /dev/null +++ b/plugins/tidypics/views/rss/extensions/tidypics/xmlns.php @@ -0,0 +1 @@ + xmlns:media="http://search.yahoo.com/mrss/" \ No newline at end of file diff --git a/plugins/tidypics/views/rss/object/album.php b/plugins/tidypics/views/rss/object/album.php new file mode 100644 index 0000000000000000000000000000000000000000..8542b95f4595831444cd24fab31f4786a95c0a4c --- /dev/null +++ b/plugins/tidypics/views/rss/object/album.php @@ -0,0 +1,54 @@ +<?php + /** + * Tidypics Album RSS View + */ + +// for now catch the albums view and ignore it +if (get_context() == "search" && get_input('search_viewtype') == "gallery") { +?> + <item> + <guid isPermaLink='true'><?php echo $vars['entity']->getURL(); ?></guid> + <pubDate><?php echo date("r",$vars['entity']->time_created) ?></pubDate> + <link><?php echo $vars['entity']->getURL(); ?></link> + <title><![CDATA[<?php echo $vars['entity']->title; ?>]]></title> + <description><![CDATA[<?php echo (autop($vars['entity']->description)); ?>]]></description> + </item> + +<?php +} else { + + $album = $vars['entity']; + + // use fullsize image + $base_url_fullsize = $vars['url'] . 'pg/photos/download/'; + + // insert cover image if it exists image + if ($album->cover) { + // Set title + $vars['title'] = $album->title; + if (empty($vars['title'])) { + $title = $vars['config']->sitename; + } else if (empty($vars['config']->sitename)) { + $title = $vars['title']; + } else { + $title = $vars['config']->sitename . ": " . $vars['title']; + } + $album_cover_url = $vars['url'] . 'mod/tidypics/thumbnail.php?file_guid=' . $album->cover . '&size=thumb'; +?> <image> + <url><?php echo $album_cover_url; ?></url> + <title><![CDATA[<?php echo $title; ?>]]></title> + <link><?php echo $album->getURL() . '?view=rss'; ?></link> + </image> +<?php + } + + + $images = get_entities("object", "image", 0, "", 0, 0, false, 0, $album->guid); + + + foreach ($images as $image) { + echo elgg_view_entity($image); + } + +} +?> \ No newline at end of file diff --git a/plugins/tidypics/views/rss/object/file.php b/plugins/tidypics/views/rss/object/file.php new file mode 100644 index 0000000000000000000000000000000000000000..36740f0031b6652bd722cf2a773fcae5b112782c --- /dev/null +++ b/plugins/tidypics/views/rss/object/file.php @@ -0,0 +1,23 @@ +<?php + + /** + * Tidypics RSS file object view - need to look into removing download link based on settings + */ + + $title = $vars['entity']->title; + if (empty($title)) { + $title = substr($vars['entity']->description,0,32); + if (strlen($vars['entity']->description) > 32) + $title .= " ..."; + } + +?> + + <item> + <guid isPermaLink='true'><?php echo $vars['entity']->getURL(); ?></guid> + <pubDate><?php echo date("r",$vars['entity']->time_created) ?></pubDate> + <link><?php echo $vars['entity']->getURL(); ?></link> + <title><![CDATA[<?php echo $title; ?>]]></title> + <description><![CDATA[<?php echo (autop($vars['entity']->description)); ?>]]></description> + <enclosure url="<?php echo $vars['url']; ?>pg/photos/download/<?php echo $vars['entity']->getGUID(); ?>/" length="<?php echo $vars['entity']->size(); ?>" type="<?php echo $vars['entity']->getMimeType(); ?>" /> + </item> diff --git a/plugins/tidypics/views/rss/object/image.php b/plugins/tidypics/views/rss/object/image.php new file mode 100644 index 0000000000000000000000000000000000000000..b9359208196b0b0ec27cf1c3e26f1c65c564d421 --- /dev/null +++ b/plugins/tidypics/views/rss/object/image.php @@ -0,0 +1,19 @@ +<?php + +$title = $vars['entity']->title; +$descr = $vars['entity']->description; +$download = $vars['url'] . 'pg/photos/download/' . $vars['entity']->guid . '/inline/'; +$base_url = $vars['url'] . 'mod/tidypics/thumbnail.php?file_guid='; +?> + + <item> + <title><?php echo $title; ?></title> + <link><?php echo $base_url . $vars['entity']->guid . '&size=large'; ?></link> + <description><?php echo htmlentities($descr, ENT_QUOTES); ?></description> + <pubDate><?php echo date("r", $vars['entity']->time_created); ?></pubDate> + <guid isPermaLink="true"><?php echo $vars['entity']->getURL(); ?></guid> + <media:content url="<?php echo $download; ?>" medium="image" type="<?php echo $vars['entity']->getMimeType(); ?>" /> + <media:title><?php echo $title; ?></media:title> + <media:description><?php echo htmlentities($descr); ?></media:description> + <media:thumbnail url="<?php echo $base_url . $vars['entity']->guid . '&size=thumb'; ?>"></media:thumbnail> + </item> \ No newline at end of file diff --git a/plugins/tidypics/views/rss/pageshells/pageshell.php b/plugins/tidypics/views/rss/pageshells/pageshell.php new file mode 100644 index 0000000000000000000000000000000000000000..2dfc8917f509cbcb7dc7618447dde76b12e2a92b --- /dev/null +++ b/plugins/tidypics/views/rss/pageshells/pageshell.php @@ -0,0 +1,46 @@ +<?php + + /** + * Elgg RSS output pageshell + * + * @package Elgg + * @subpackage Core + * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2 + * @copyright Curverider Ltd 2008-2009 + * @link http://elgg.org/ + * + */ + + header("Content-Type: text/xml"); + + echo "<?xml version='1.0'?>\n"; + + + + // Set title + if (empty($vars['title'])) { + $title = $vars['config']->sitename; + } else if (empty($vars['config']->sitename)) { + $title = $vars['title']; + } else { + $title = $vars['config']->sitename . ": " . $vars['title']; + } + + // Remove RSS from URL + $url = str_replace('?view=rss','',full_url()); + $url = str_replace('&view=rss','',full_url()); + +?> + +<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:georss="http://www.georss.org/georss" <?php echo elgg_view('extensions/xmlns'); ?> > + <channel> + <title><![CDATA[<?php echo $title; ?>]]></title> + <link><?php echo htmlentities($url); ?></link> + <?php echo elgg_view('extensions/channel'); ?> + <?php + + echo $vars['body']; + + ?> + </channel> +</rss> \ No newline at end of file diff --git a/plugins/tidypics/views/rss/tidypics/content_wrapper.php b/plugins/tidypics/views/rss/tidypics/content_wrapper.php new file mode 100644 index 0000000000000000000000000000000000000000..0b16f23576d2386d9938d47ade5fefa0f27b45a3 --- /dev/null +++ b/plugins/tidypics/views/rss/tidypics/content_wrapper.php @@ -0,0 +1,2 @@ +<?php +echo $vars['content']; diff --git a/plugins/tidypics/views/rss/tidypics/gallery.php b/plugins/tidypics/views/rss/tidypics/gallery.php new file mode 100644 index 0000000000000000000000000000000000000000..2c285fca52eb846f8eafbca877637fcb5d47d77c --- /dev/null +++ b/plugins/tidypics/views/rss/tidypics/gallery.php @@ -0,0 +1,18 @@ +<?php + /** + * Tidypics Listing RSS View + */ + +$context = $vars['context']; +$entities = $vars['entities']; +$count = $vars['count']; +$baseurl = $vars['baseurl']; + + +if (is_array($entities) && sizeof($entities) > 0) { + foreach($entities as $entity) { + echo elgg_view_entity($entity); + } +} + +?> \ No newline at end of file