Added initial support for notes (aka tags) on images, done completely (including initial load of metadata) with AJAX. They're not fixed at 100x100 like on Facebook either.
<?php/* * Snapr * Version 0.1 beta 1 * Copyright (C) 2007 Dan Fuhry * * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. *//** * Generates a random filename for Snapr images. * @param int $length Optional - length of filename * @return string */function gallery_make_filename($length = 24){ $valid_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; $valid_chars = enano_str_split($valid_chars); $ret = ''; for ( $i = 0; $i < $length; $i++ ) { $ret .= $valid_chars[mt_rand(0, count($valid_chars)-1)]; } return $ret;}/** * Returns the extension of a file. * @param string file * @return string */function get_file_extension($file){ return substr($file, ( strrpos($file, '.') + 1 ));}/** * For a given image ID, return the folder hierarchy. * @param int The image ID * @return array */function gallery_imgid_to_folder($img_id){ global $db, $session, $paths, $template, $plugins; // Common objects if ( !is_int($img_id) ) return array(); $img_id = strval($img_id); $ret = array(); $sanity = 0; $sanity_stack = array(); while(true) { $sanity++; $q = $db->sql_query('SELECT img_title, img_id, folder_parent FROM '.table_prefix.'gallery WHERE img_id=' . $img_id . ';'); if ( !$q ) $db->_die(); $row = $db->fetchrow(); if ( !$row ) { break; } if ( $sanity > 1 ) { $ret[] = $row['img_title']; } if ( !$row['folder_parent'] ) { break; } if ( in_array($row['img_id'], $sanity_stack) ) return array('Infinite loop'); $sanity_stack[] = $row['img_id']; $img_id = $row['folder_parent']; } return $ret;}/** * Generates a hierarchy of Gallery folders. * @return array */function gallery_folder_hierarchy(){ global $db, $session, $paths, $template, $plugins; // Common objects $q = $db->sql_query('SELECT img_id, img_title, folder_parent FROM '.table_prefix.'gallery WHERE is_folder=1'); if ( !$q ) $db->_die(); if ( $db->numrows() < 1 ) { return array(); } $lookup_table = array(); $hier = array('_id' => 'NULL'); $orphans = array(); $persist_orphans = array(); while ( $row = $db->fetchrow() ) { if ( !$row['folder_parent'] ) { // root-level folder $hier[ $row['img_title'] ] = array('_id' => $row['img_id']); $lookup_table[$row['img_id']] =& $hier[ $row['img_title'] ]; } else if ( $row['folder_parent'] && isset($lookup_table[$row['folder_parent']]) ) { // child folder, parent is resolved $lookup_table[ $row['folder_parent'] ][ $row['img_title'] ] = array('_id' => $row['img_id']); $lookup_table[ $row['img_id'] ] =& $lookup_table[ $row['folder_parent'] ][ $row['img_title'] ]; } else if ( $row['folder_parent'] && !isset($lookup_table[$row['folder_parent']]) ) { // child folder, orphan as of yet $orphans[] = $row; } } // Resolve orphans do { $persist_orphans = array(); while ( count($orphans) > 0 ) { $orphan =& $orphans[ ( count($orphans) - 1 ) ]; if ( isset($lookup_table[$orphan['folder_parent']]) ) { $lookup_table[ $orphan['folder_parent'] ][ $orphan['img_title'] ] = array('_id' => $orphan['img_id']); $lookup_table[ $orphan['img_id'] ] =& $lookup_table[ $orphan['folder_parent'] ][ $orphan['img_title'] ]; } else { $persist_orphans[] = $orphans[ ( count($orphans) - 1 ) ]; //echo 'BUG: ' . htmlspecialchars($orphan['img_title']) . ' (' . $orphan['img_id'] . ') is an orphan folder (parent is ' . $orphan['folder_parent'] . '); placing in root<br />'; // $hier[ $orphan['img_title'] ] = array(); // $lookup_table[$orphan['img_id']] =& $hier[ $orphan['img_title'] ]; } unset($orphan, $orphans[ ( count($orphans) - 1 ) ]); } $orphans = $persist_orphans; //die('insanity:<pre>'.print_r($hier,true).print_r($lookup_table,true).print_r($persist_orphans,true).'</pre>'); } while ( count($persist_orphans) > 0 ); return $hier;}/** * Generates HTML for a folder selector. * @param string The form field name, defaults to folder_id. * @param bool Whether to auto-select the root or not. Defaults to true. * @return string */function gallery_hier_formfield($field_name = 'folder_id', $autosel = true){ $hier = gallery_folder_hierarchy(); $img_join = scriptPath . '/images/icons/joinbottom.gif'; $img_join_term = scriptPath . '/images/icons/join.gif'; $img_line = scriptPath . '/images/icons/line.gif'; $img_empty = scriptPath . '/images/icons/empty.gif'; $html = _gallery_hier_form_inner($hier, '<Root>', $field_name, -1, array(), $img_join, $img_join_term, $img_line, $img_empty, $autosel); return $html;}// /** * Inner loop for form field generator (needs to call itself recursively) * @access private */function _gallery_hier_form_inner($el, $name, $fname, $depth, $depth_img, $img_join, $img_join_term, $img_line, $img_empty, $sel = false){ $html = ''; foreach ( $depth_img as $sw ) $html .= '<img alt=" " src="' . $sw . '" />'; $html .= '<label><input ' . ( $sel ? 'checked="checked"' : '' ) . ' type="radio" name="' . $fname . '" value="' . $el['_id'] . '" /> ' . htmlspecialchars($name) . '</label><br />'; if ( count($el) > 1 ) { // Writing this image logic sucked. $count = 0; foreach ( $el as $key => $el_lower ) { $count++; if ( $key == '_id' ) continue; $depth_mod = $depth_img; $last = ( $count == count($el) ); for ( $i = 0; $i < count($depth_mod); $i++ ) { if ( $depth_mod[$i] == $img_join_term || $depth_mod[$i] == $img_empty ) $depth_mod[$i] = $img_empty; else $depth_mod[$i] = $img_line; } if ( $last ) $depth_mod[] = $img_join_term; else $depth_mod[] = $img_join; $html .= _gallery_hier_form_inner($el_lower, $key, $fname, ( $depth + 1 ), $depth_mod, $img_join, $img_join_term, $img_line, $img_empty); } } return $html;}/** * Returns an array containing the IDs of all of the given folder ID's children. Recursive function. * @param int ID of folder */function gal_fetch_all_children($id){ global $db, $session, $paths, $template, $plugins; // Common objects if ( !is_int($id) ) { die('not int'); return false; } $children = array(); $q = $db->sql_query('SELECT img_id,is_folder FROM '.table_prefix.'gallery WHERE folder_parent=' . $id . ';'); if ( !$q ) $db->_die(); if ( $db->numrows() < 1 ) { return $children; } $folders = array(); while ( $row = $db->fetchrow() ) { $children[] = intval($row['img_id']); if ( $row['is_folder'] == 1 ) $folders[] = intval($row['img_id']); } foreach ( $folders as $folder ) { $grandchildren = gal_fetch_all_children($folder); if ( $grandchildren === false ) { return false; } $children = array_merge($children, $grandchildren); } return $children;}/** * Lists all normal files within a given directory. Recursive function. Can also return the list of directories in the second parameter by reference. * @param string Directory to search * @param array Variable in which to store * @return array Not multi-depth */function gal_dir_recurse($dir, &$dirlist){ $dir_handle = opendir($dir); if ( !$dir_handle ) return false; $entries = array(); $dirlist = array(); while ( true ) { $file = readdir($dir_handle); if ( !$file ) break; if ( $file == '.' || $file == '..' ) continue; $file = $dir . '/' . $file; if ( is_dir($file) ) { $children = gal_dir_recurse($file, $dirtemp); $dirlist[] = $file; $dirlist = array_merge($dirlist, $dirtemp); $entries = array_merge($entries, $children); } else if ( is_file($file) ) { $entries[] = $file; } else { die($file . ' is not a file or directory'); } } closedir($dir_handle); return $entries;}/** * Wrapper for JSON decoding that works on Enano 1.0.x and 1.1.x * @param string JSON datastream... * @return mixed */function snapr_json_decode($data){ if ( defined('ENANO_ATLEAST_1_1') ) { try { $decoded = enano_json_decode($data); } catch ( Exception $e ) { $response = array( 'mode' => 'error', 'error' => 'Exception in JSON parser.' ); die(enano_json_encode($response)); } } else { $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); $decoded = $json->decode($data); } return ( isset($decoded) ) ? $decoded : false;}/** * Wrapper for JSON encoding that works on Enano 1.0.x and 1.1.x * @param mixed Data to encode * @return string */function snapr_json_encode($data){ if ( defined('ENANO_ATLEAST_1_1') ) { try { $encoded = enano_json_encode($data); } catch ( Exception $e ) { $response = array( 'mode' => 'error', 'error' => 'Exception in JSON encoder.' ); die(enano_json_encode($response)); } } else { $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); $encoded = $json->encode($data); } return ( isset($encoded) ) ? $encoded : false;}?>