diff --git a/.htaccess b/.htaccess index 0189d10..5332f1b 100644 --- a/.htaccess +++ b/.htaccess @@ -1,12 +1,12 @@ - - RewriteEngine On - RewriteCond %{REQUEST_FILENAME} !-f - RewriteRule ^(.*)$ serviceapp.php [QSA,L] - - - - Allow from *.gruppolapastamadre.it - - -Header set Access-Control-Allow-Origin *.gruppolapastamadre.it -Header set Access-Control-Allow-Methods: "GET,POST,OPTIONS,DELETE,PUT" \ No newline at end of file + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^(.*)$ serviceapp.php [QSA,L] + + + +# Allow from app.gruppolapastamadre.it + + +#Header set Access-Control-Allow-Origin "app.gruppolapastamadre.it" +#Header set Access-Control-Allow-Methods: "GET,POST,OPTIONS,DELETE,PUT" \ No newline at end of file diff --git a/DropBoxPhp/DropboxClient.php b/DropBoxPhp/DropboxClient.php new file mode 100644 index 0000000..426dbfe --- /dev/null +++ b/DropBoxPhp/DropboxClient.php @@ -0,0 +1,681 @@ + + * @copyright Fabian Schlieper 2012 + * @version 1.7 + * @license See LICENSE + * + */ + +require_once(dirname(__FILE__)."/OAuthSimple.php"); + +class DropboxClient { + + const API_URL = "https://api.dropbox.com/1/"; + const API_CONTENT_URL = "https://api-content.dropbox.com/1/"; + + const BUFFER_SIZE = 4096; + + const MAX_UPLOAD_CHUNK_SIZE = 150000000; // 150MB + + const UPLOAD_CHUNK_SIZE = 4000000; // 4MB + + private $appParams; + private $consumerToken; + + private $requestToken; + private $accessToken; + + private $locale; + private $rootPath; + + private $useCurl; + + function __construct ($app_params, $locale = "en"){ + $this->appParams = $app_params; + if(empty($app_params['app_key'])) + throw new DropboxException("App Key is empty!"); + + $this->consumerToken = array('t' => $this->appParams['app_key'], 's' => $this->appParams['app_secret']); + $this->locale = $locale; + $this->rootPath = empty($app_params['app_full_access']) ? "sandbox" : "dropbox"; + + $this->requestToken = null; + $this->accessToken = null; + + $this->useCurl = function_exists('curl_init'); + } + + /** + * Sets whether to use cURL if its available or PHP HTTP wrappers otherwise + * + * @access public + * @return boolean Whether to actually use cURL (always false if not installed) + */ + public function SetUseCUrl($use_it) + { + return ($this->useCurl = ($use_it && function_exists('curl_init'))); + } + + // ################################################## + // Authorization + + /** + * Step 1 of authentication process. Retrieves a request token or returns a previously retrieved one. + * + * @access public + * @param boolean $get_new_token Optional (default false). Wether to retrieve a new request token. + * @return array Request Token array. + */ + public function GetRequestToken($get_new_token=false) + { + if(!empty($this->requestToken) && !$get_new_token) + return $this->requestToken; + + $rt = $this->authCall("oauth/request_token"); + if(empty($rt) || empty($rt['oauth_token'])) + throw new DropboxException('Could not get request token!'); + + return ($this->requestToken = array('t'=>$rt['oauth_token'], 's'=>$rt['oauth_token_secret'])); + } + + /** + * Step 2. Returns a URL the user must be redirected to in order to connect the app to their Dropbox account + * + * @access public + * @param string $return_url URL users are redirected after authorization + * @return string URL + */ + public function BuildAuthorizeUrl($return_url) + { + $rt = $this->GetRequestToken(); + if(empty($rt) || empty($rt['t'])) throw new DropboxException('Request Token Invalid ('.print_r($rt,true).').'); + return "https://www.dropbox.com/1/oauth/authorize?oauth_token=".$rt['t']."&oauth_callback=".urlencode($return_url); + } + + /** + * Step 3. Acquires an access token. This is the final step of authentication. + * + * @access public + * @param array $request_token Optional. The previously retrieved request token. This parameter can only be skipped if the DropboxClient object has been (de)serialized. + * @return array Access Token array. + */ + public function GetAccessToken($request_token = null) + { + if(!empty($this->accessToken)) return $this->accessToken; + + if(empty($request_token)) $request_token = $this->requestToken; + if(empty($request_token)) throw new DropboxException('Request token required!'); + + $at = $this->authCall("oauth/access_token", $request_token); + if(empty($at)) + throw new DropboxException(sprintf('Could not get access token! (request token: %s)', $request_token['t'])); + + return ($this->accessToken = array('t'=>$at['oauth_token'], 's'=>$at['oauth_token_secret'])); + } + + /** + * Sets a previously retrieved (and stored) access token. + * + * @access public + * @param string|object $token The Access Token + * @return none + */ + public function SetAccessToken($token) + { + if(empty($token['t']) || empty($token['s'])) throw new DropboxException('Passed invalid access token.'); + $this->accessToken = $token; + } + + /** + * Checks if an access token has been set. + * + * @access public + * @return boolean Authorized or not + */ + public function IsAuthorized() + { + if(empty($this->accessToken)) return false; + return true; + } + + + // ################################################## + // API Functions + + + /** + * Retrieves information about the user's account. + * + * @access public + * @return object Account info object. See https://www.dropbox.com/developers/reference/api#account-info + */ + public function GetAccountInfo() + { + return $this->apiCall("account/info", "GET"); + } + + + /** + * Get file list of a dropbox folder. + * + * @access public + * @param string|object $dropbox_path Dropbox path of the folder + * @return array An array with metadata of files/folders keyed by paths + */ + public function GetFiles($dropbox_path='', $recursive=false, $include_deleted=false) + { + if(is_object($dropbox_path) && !empty($dropbox_path->path)) $dropbox_path = $dropbox_path->path; + return $this->getFileTree($dropbox_path, $include_deleted, $recursive ? 1000 : 0); + } + + /** + * Get file or folder metadata + * + * @access public + * @param $dropbox_path string Dropbox path of the file or folder + */ + public function GetMetadata($dropbox_path, $include_deleted=false, $rev=null) + { + if(is_object($dropbox_path) && !empty($dropbox_path->path)) $dropbox_path = $dropbox_path->path; + return $this->apiCall("metadata/$this->rootPath/$dropbox_path", "GET", compact('include_deleted','rev')); + } + + /** + * Download a file to the webserver + * + * @access public + * @param string|object $dropbox_file Dropbox path or metadata object of the file to download. + * @param string $dest_path Local path for destination + * @param string $rev Optional. The revision of the file to retrieve. This defaults to the most recent revision. + * @param callback $progress_changed_callback Optional. Callback that will be called during download with 2 args: 1. bytes loaded, 2. file size + * @return object Dropbox file metadata + */ + public function DownloadFile($dropbox_file, $dest_path='', $rev=null, $progress_changed_callback = null) + { + if(is_object($dropbox_file) && !empty($dropbox_file->path)) + $dropbox_file = $dropbox_file->path; + + if(empty($dest_path)) $dest_path = basename($dropbox_file); + + $url = $this->cleanUrl(self::API_CONTENT_URL."/files/$this->rootPath/$dropbox_file") + . (!empty($rev) ? ('?'.http_build_query(array('rev' => $rev),'','&')) : ''); + $context = $this->createRequestContext($url, "GET"); + + $fh = @fopen($dest_path, 'wb'); // write binary + if($fh === false) { + @fclose($rh); + throw new DropboxException("Could not create file $dest_path !"); + } + + if($this->useCurl) { + curl_setopt($context, CURLOPT_BINARYTRANSFER, true); + curl_setopt($context, CURLOPT_RETURNTRANSFER, true); + curl_setopt($context, CURLOPT_FILE, $fh); + $response_headers = array(); + self::execCurlAndClose($context, $response_headers); + fclose($fh); + $meta = self::getMetaFromHeaders($response_headers, true); + $bytes_loaded = filesize($dest_path); + } else { + $rh = @fopen($url, 'rb', false, $context); // read binary + if($rh === false) + throw new DropboxException("HTTP request to $url failed!"); + + + // get file meta from HTTP header + $s_meta = stream_get_meta_data($rh); + $meta = self::getMetaFromHeaders($s_meta['wrapper_data'], true); + $bytes_loaded = 0; + while (!feof($rh)) { + if(($s=fwrite($fh, fread($rh, self::BUFFER_SIZE))) === false) { + @fclose($rh); + @fclose($fh); + throw new DropboxException("Writing to file $dest_path failed!'"); + } + $bytes_loaded += $s; + if(!empty($progress_changed_callback)) { + call_user_func($progress_changed_callback, $bytes_loaded, $meta->bytes); + } + } + + fclose($rh); + fclose($fh); + } + + if($meta->bytes != $bytes_loaded) + throw new DropboxException("Download size mismatch! (header:{$meta->bytes} vs actual:{$bytes_loaded}; curl:{$this->useCurl})"); + + return $meta; + } + + /** + * Upload a file to dropbox + * + * @access public + * @param $src_file string Local file to upload + * @param $dropbox_path string Dropbox path for destination + * @return object Dropbox file metadata + */ + public function UploadFile($src_file, $dropbox_path='', $overwrite=true, $parent_rev=null) + { + if(empty($dropbox_path)) $dropbox_path = basename($src_file); + elseif(is_object($dropbox_path) && !empty($dropbox_path->path)) $dropbox_path = $dropbox_path->path; + + // make sure the dropbox_path is not a dir. if it is, append baseneme of $src_file + $dropbox_bn = basename($dropbox_path); + if(strpos($dropbox_bn,'.') === false) { // check if ext. is missing -> could be a directory! + try { + $meta = $this->GetMetadata($dropbox_path); + if($meta && $meta->is_dir) + $dropbox_path = $dropbox_path . '/'. basename($src_file); + } catch(Exception $e) {} + } + + $file_size = filesize($src_file); + + if($file_size > self::MAX_UPLOAD_CHUNK_SIZE) + { + $fh = fopen($src_file,'rb'); + if($fh === false) + throw new DropboxException(); + + $upload_id = null; + $offset = 0; + + + while(!feof($fh)) { + $url = $this->cleanUrl(self::API_CONTENT_URL."/chunked_upload").'?'.http_build_query(compact('upload_id', 'offset'),'','&'); + + if($this->useCurl) { + $context = $this->createRequestContext($url, "PUT"); + curl_setopt($context, CURLOPT_BINARYTRANSFER, true); + curl_setopt($context, CURLOPT_PUT, 1); + curl_setopt($context, CURLOPT_INFILE, $fh); + $chunk_size = min(self::UPLOAD_CHUNK_SIZE, $file_size - $offset); + $offset += $chunk_size; + curl_setopt($context, CURLOPT_INFILESIZE, $chunk_size); + $response = json_decode(self::execCurlAndClose($context)); + + fseek($fh,$offset); + if($offset >= $file_size) + break; + } else { + $content = fread($fh, self::UPLOAD_CHUNK_SIZE); + + $context = $this->createRequestContext($url, "PUT", $content); + $offset += strlen($content); + unset($content); + + $response = json_decode(file_get_contents($url, false, $context)); + } + unset($context); + + self::checkForError($response); + + if(empty($upload_id)) { + $upload_id = $response->upload_id; + if(empty($upload_id)) throw new DropboxException("Upload ID empty!"); + } + } + + @fclose($fh); + + $this->useCurl = $prev_useCurl; + + return $this->apiCall("commit_chunked_upload/$this->rootPath/$dropbox_path", "POST", compact('overwrite','parent_rev','upload_id'), true); + } + + $query = http_build_query(array_merge(compact('overwrite', 'parent_rev'), array('locale' => $this->locale)),'','&'); + $url = $this->cleanUrl(self::API_CONTENT_URL."/files_put/$this->rootPath/$dropbox_path")."?$query"; + + if($this->useCurl) { + $context = $this->createRequestContext($url, "PUT"); + curl_setopt($context, CURLOPT_BINARYTRANSFER, true); + $fh = fopen($src_file, 'rb'); + curl_setopt($context, CURLOPT_PUT, 1); + curl_setopt($context, CURLOPT_INFILE, $fh); // file pointer + curl_setopt($context, CURLOPT_INFILESIZE, filesize($src_file)); + $meta = json_decode(self::execCurlAndClose($context)); + fclose($fh); + return self::checkForError($meta); + } else { + $content = file_get_contents($src_file); + if(strlen($content) == 0) + throw new DropboxException("Could not read file $src_file or file is empty!"); + + $context = $this->createRequestContext($url, "PUT", $content); + + return self::checkForError(json_decode(file_get_contents($url, false, $context))); + } + } + + /** + * Get thumbnail for a specified image + * + * @access public + * @param $dropbox_file string Path to the image + * @param $format string Image format of the thumbnail (jpeg or png) + * @param $size string Thumbnail size (xs, s, m, l, xl) + * @return mime/* Returns the thumbnail as binary image data + */ + public function GetThumbnail($dropbox_file, $size = 's', $format = 'jpeg', $echo = false) + { + if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path; + $url = $this->cleanUrl(self::API_CONTENT_URL."thumbnails/$this->rootPath/$dropbox_file") + . '?' . http_build_query(array('format' => $format, 'size' => $size),'','&'); + $context = $this->createRequestContext($url, "GET"); + + if($this->useCurl) { + curl_setopt($context, CURLOPT_BINARYTRANSFER, true); + curl_setopt($context, CURLOPT_RETURNTRANSFER, true); + } + + $thumb = $this->useCurl ? self::execCurlAndClose($context) : file_get_contents($url, NULL, $context); + + if($echo) { + header('Content-type: image/'.$format); + echo $thumb; + unset($thumb); + return; + } + + return $thumb; + } + + + function GetLink($dropbox_file, $preview=true, $short=true, &$expires=null) + { + if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path; + $url = $this->apiCall(($preview?"shares":"media")."/$this->rootPath/$dropbox_file", "POST", array('locale' => null, 'short_url'=> $preview ? $short : null)); + $expires = strtotime($url->expires); + return $url->url; + } + + function Delta($cursor) + { + return $this->apiCall("delta", "POST", compact('cursor')); + } + + function GetRevisions($dropbox_file, $rev_limit=10) + { + if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path; + return $this->apiCall("revisions/$this->rootPath/$dropbox_file", "GET", compact('rev_limit')); + } + + function Restore($dropbox_file, $rev) + { + if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path; + return $this->apiCall("restore/$this->rootPath/$dropbox_file", "POST", compact('rev')); + } + + function Search($path, $query, $file_limit=1000, $include_deleted=false) + { + return $this->apiCall("search/$this->rootPath/$path", "POST", compact('query','file_limit','include_deleted')); + } + + function GetCopyRef($dropbox_file, &$expires=null) + { + if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path; + $ref = $this->apiCall("copy_ref/$this->rootPath/$dropbox_file", "GET", array('locale' => null)); + $expires = strtotime($ref->expires); + return $ref->copy_ref; + } + + + function Copy($from_path, $to_path, $copy_ref=false) + { + if(is_object($from_path) && !empty($from_path->path)) $from_path = $from_path->path; + return $this->apiCall("fileops/copy", "POST", array('root'=> $this->rootPath, ($copy_ref ? 'from_copy_ref' : 'from_path') => $from_path, 'to_path' => $to_path)); + } + + /** + * Creates a new folder in the DropBox + * + * @access public + * @param $path string The path to the new folder to create + * @return object Dropbox folder metadata + */ + function CreateFolder($path) + { + return $this->apiCall("fileops/create_folder", "POST", array('root'=> $this->rootPath, 'path' => $path)); + } + + /** + * Delete file or folder + * + * @access public + * @param $path mixed The path or metadata of the file/folder to be deleted. + * @return object Dropbox metadata of deleted file or folder + */ + function Delete($path) + { + if(is_object($path) && !empty($path->path)) $path = $path->path; + return $this->apiCall("fileops/delete", "POST", array('locale' =>null, 'root'=> $this->rootPath, 'path' => $path)); + } + + function Move($from_path, $to_path) + { + if(is_object($from_path) && !empty($from_path->path)) $from_path = $from_path->path; + return $this->apiCall("fileops/move", "POST", array('root'=> $this->rootPath, 'from_path' => $from_path, 'to_path' => $to_path)); + } + + function getFileTree($path="", $include_deleted = false, $max_depth = 0, $depth=0) + { + static $files; + if($depth == 0) $files = array(); + + $dir = $this->apiCall("metadata/$this->rootPath/$path", "GET", compact('include_deleted')); + + if(empty($dir) || !is_object($dir)) return false; + + if(!empty($dir->error)) throw new DropboxException($dir->error); + + foreach($dir->contents as $item) + { + $files[trim($item->path,'/')] = $item; + if($item->is_dir && $depth < $max_depth) + { + $this->getFileTree($item->path, $include_deleted, $max_depth, $depth+1); + } + } + + return $files; + } + + function createCurl($url, $http_context) + { + $ch = curl_init($url); + + $curl_opts = array( + CURLOPT_HEADER => false, // exclude header from output + //CURLOPT_MUTE => true, // no output! + CURLOPT_RETURNTRANSFER => true, // but return! + CURLOPT_SSL_VERIFYPEER => false, + ); + + $curl_opts[CURLOPT_CUSTOMREQUEST] = $http_context['method']; + + if(!empty($http_context['content'])) { + $curl_opts[CURLOPT_POSTFIELDS] =& $http_context['content']; + if(defined("CURLOPT_POSTFIELDSIZE")) + $curl_opts[CURLOPT_POSTFIELDSIZE] = strlen($http_context['content']); + } + + $curl_opts[CURLOPT_HTTPHEADER] = array_map('trim',explode("\n",$http_context['header'])); + + curl_setopt_array($ch, $curl_opts); + return $ch; + } + + static private $_curlHeadersRef; + static function _curlHeaderCallback($ch, $header) + { + self::$_curlHeadersRef[] = trim($header); + return strlen($header); + } + + static function &execCurlAndClose($ch, &$out_response_headers = null) + { + if(is_array($out_response_headers)) { + self::$_curlHeadersRef =& $out_response_headers; + curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(__CLASS__, '_curlHeaderCallback')); + } + $res = curl_exec($ch); + $err_no = curl_errno($ch); + $err_str = curl_error($ch); + curl_close($ch); + if($err_no || $res === false) { + throw new DropboxException("cURL-Error ($err_no): $err_str"); + } + + return $res; + } + + private function createRequestContext($url, $method, &$content=null, $oauth_token=-1) + { + if($oauth_token === -1) + $oauth_token = $this->accessToken; + + $method = strtoupper($method); + $http_context = array('method'=>$method, 'header'=> ''); + + $oauth = new OAuthSimple($this->consumerToken['t'],$this->consumerToken['s']); + + if(empty($oauth_token) && !empty($this->accessToken)) + $oauth_token = $this->accessToken; + + if(!empty($oauth_token)) { + $oauth->setParameters(array('oauth_token' => $oauth_token['t'])); + $oauth->signatures(array('oauth_secret'=>$oauth_token['s'])); + } + + if(!empty($content)) { + $post_vars = ($method != "PUT" && preg_match("/^[a-z][a-z0-9_]*=/i", substr($content, 0, 32))); + $http_context['header'] .= "Content-Length: ".strlen($content)."\r\n"; + $http_context['header'] .= "Content-Type: application/".($post_vars?"x-www-form-urlencoded":"octet-stream")."\r\n"; + $http_context['content'] =& $content; + if($method == "POST" && $post_vars) + $oauth->setParameters($content); + } elseif($method == "POST") { + // make sure that content-length is always set when post request (otherwise some wrappers fail!) + $http_context['content'] = ""; + $http_context['header'] .= "Content-Length: 0\r\n"; + } + + + // check for query vars in url and add them to oauth parameters (and remove from path) + $path = $url; + $query = strrchr($url,'?'); + if(!empty($query)) { + $oauth->setParameters(substr($query,1)); + $path = substr($url, 0, -strlen($query)); + } + + + $signed = $oauth->sign(array( + 'action' => $method, + 'path'=> $path)); + //print_r($signed); + + $http_context['header'] .= "Authorization: ".$signed['header']."\r\n"; + + return $this->useCurl ? $this->createCurl($url, $http_context) : stream_context_create(array('http'=>$http_context)); + } + + private function authCall($path, $request_token=null) + { + $url = $this->cleanUrl(self::API_URL.$path); + $dummy = null; + $context = $this->createRequestContext($url, "POST", $dummy, $request_token); + + $contents = $this->useCurl ? self::execCurlAndClose($context) : file_get_contents($url, false, $context); + $data = array(); + parse_str($contents, $data); + return $data; + } + + private static function checkForError($resp) + { + if(!empty($resp->error)) + throw new DropboxException($resp->error); + return $resp; + } + + + private function apiCall($path, $method, $params=array(), $content_call=false) + { + $url = $this->cleanUrl(($content_call ? self::API_CONTENT_URL : self::API_URL).$path); + $content = http_build_query(array_merge(array('locale'=>$this->locale), $params),'','&'); + + if($method == "GET") { + $url .= "?".$content; + $content = null; + } + + $context = $this->createRequestContext($url, $method, $content); + $json = $this->useCurl ? self::execCurlAndClose($context) : file_get_contents($url, false, $context); + //if($json === false) +// throw new DropboxException(); + $resp = json_decode($json); + return self::checkForError($resp); + } + + + private static function getMetaFromHeaders(&$header_array, $throw_on_error=false) + { + $obj = json_decode(substr(@array_shift(array_filter($header_array, create_function('$s', 'return stripos($s, "x-dropbox-metadata:") === 0;'))), 20)); + if($throw_on_error && (empty($obj)||!is_object($obj))) + throw new DropboxException("Could not retrieve meta data from header data: ".print_r($header_array,true)); + if($throw_on_error) + self::checkForError ($obj); + return $obj; + } + + + function cleanUrl($url) { + $p = substr($url,0,8); + $url = str_replace('//','/', str_replace('\\','/',substr($url,8))); + $url = rawurlencode($url); + $url = str_replace('%2F', '/', $url); + return $p.$url; + } +} + +class DropboxException extends Exception { + + public function __construct($err = null, $isDebug = FALSE) + { + if(is_null($err)) { + $el = error_get_last(); + $this->message = $el['message']; + $this->file = $el['file']; + $this->line = $el['line']; + } else + $this->message = $err; + self::log_error($err); + if ($isDebug) + { + self::display_error($err, TRUE); + } + } + + public static function log_error($err) + { + error_log($err, 0); + } + + public static function display_error($err, $kill = FALSE) + { + print_r($err); + if ($kill === FALSE) + { + die(); + } + } +} diff --git a/DropBoxPhp/OAuthSimple.php b/DropBoxPhp/OAuthSimple.php new file mode 100644 index 0000000..130123b --- /dev/null +++ b/DropBoxPhp/OAuthSimple.php @@ -0,0 +1,532 @@ + + * @copyright unitedHeroes.net 2011 + * @version 1.3 + * @license See OAuthSimple_license.txt + * + */ + +class OAuthSimple { + private $_secrets; + private $_default_signature_method; + private $_action; + private $_nonce_chars; + + /** + * Constructor + * + * @access public + * @param api_key (String) The API Key (sometimes referred to as the consumer key) This value is usually supplied by the site you wish to use. + * @param shared_secret (String) The shared secret. This value is also usually provided by the site you wish to use. + * @return OAuthSimple (Object) + */ + function __construct ($APIKey = "", $sharedSecret=""){ + + if (!empty($APIKey)) + { + $this->_secrets['consumer_key'] = $APIKey; + } + + if (!empty($sharedSecret)) + { + $this->_secrets['shared_secret'] = $sharedSecret; + } + + $this->_default_signature_method = "HMAC-SHA1"; + $this->_action = "GET"; + $this->_nonce_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + return $this; + } + + /** + * Reset the parameters and URL + * + * @access public + * @return OAuthSimple (Object) + */ + public function reset() { + $this->_parameters = Array(); + $this->path = NULL; + $this->sbs = NULL; + + return $this; + } + + /** + * Set the parameters either from a hash or a string + * + * @access public + * @param(string, object) List of parameters for the call, this can either be a URI string (e.g. "foo=bar&gorp=banana" or an object/hash) + * @return OAuthSimple (Object) + */ + public function setParameters ($parameters=Array()) { + + if (is_string($parameters)) + { + $parameters = $this->_parseParameterString($parameters); + } + if (empty($this->_parameters)) + { + $this->_parameters = $parameters; + } + else if (!empty($parameters)) + { + $this->_parameters = array_merge($this->_parameters,$parameters); + } + if (empty($this->_parameters['oauth_nonce'])) + { + $this->_getNonce(); + } + if (empty($this->_parameters['oauth_timestamp'])) + { + $this->_getTimeStamp(); + } + if (empty($this->_parameters['oauth_consumer_key'])) + { + $this->_getApiKey(); + } + if (empty($this->_parameters['oauth_token'])) + { + $this->_getAccessToken(); + } + if (empty($this->_parameters['oauth_signature_method'])) + { + $this->setSignatureMethod(); + } + if (empty($this->_parameters['oauth_version'])) + { + $this->_parameters['oauth_version']="1.0"; + } + + return $this; + } + + /** + * Convenience method for setParameters + * + * @access public + * @see setParameters + */ + public function setQueryString ($parameters) + { + return $this->setParameters($parameters); + } + + /** + * Set the target URL (does not include the parameters) + * + * @param path (String) the fully qualified URI (excluding query arguments) (e.g "http://example.org/foo") + * @return OAuthSimple (Object) + */ + public function setURL ($path) + { + if (empty($path)) + { + throw new OAuthSimpleException('No path specified for OAuthSimple.setURL'); + } + $this->_path=$path; + + return $this; + } + + /** + * Convenience method for setURL + * + * @param path (String) + * @see setURL + */ + public function setPath ($path) + { + return $this->_path=$path; + } + + /** + * Set the "action" for the url, (e.g. GET,POST, DELETE, etc.) + * + * @param action (String) HTTP Action word. + * @return OAuthSimple (Object) + */ + public function setAction ($action) + { + if (empty($action)) + { + $action = 'GET'; + } + $action = strtoupper($action); + if (preg_match('/[^A-Z]/',$action)) + { + throw new OAuthSimpleException('Invalid action specified for OAuthSimple.setAction'); + } + $this->_action = $action; + + return $this; + } + + /** + * Set the signatures (as well as validate the ones you have) + * + * @param signatures (object) object/hash of the token/signature pairs {api_key:, shared_secret:, oauth_token: oauth_secret:} + * @return OAuthSimple (Object) + */ + public function signatures ($signatures) + { + if (!empty($signatures) && !is_array($signatures)) + { + throw new OAuthSimpleException('Must pass dictionary array to OAuthSimple.signatures'); + } + if (!empty($signatures)) + { + if (empty($this->_secrets)) + { + $this->_secrets=Array(); + } + $this->_secrets=array_merge($this->_secrets,$signatures); + } + if (isset($this->_secrets['api_key'])) + { + $this->_secrets['consumer_key'] = $this->_secrets['api_key']; + } + if (isset($this->_secrets['access_token'])) + { + $this->_secrets['oauth_token'] = $this->_secrets['access_token']; + } + if (isset($this->_secrets['access_secret'])) + { + $this->_secrets['oauth_secret'] = $this->_secrets['access_secret']; + } + if (isset($this->_secrets['access_token_secret'])) + { + $this->_secrets['oauth_secret'] = $this->_secrets['access_token_secret']; + } + if (empty($this->_secrets['consumer_key'])) + { + throw new OAuthSimpleException('Missing required consumer_key in OAuthSimple.signatures'); + } + if (empty($this->_secrets['shared_secret'])) + { + throw new OAuthSimpleException('Missing requires shared_secret in OAuthSimple.signatures'); + } + if (!empty($this->_secrets['oauth_token']) && empty($this->_secrets['oauth_secret'])) + { + throw new OAuthSimpleException('Missing oauth_secret for supplied oauth_token in OAuthSimple.signatures'); + } + + return $this; + } + + public function setTokensAndSecrets($signatures) + { + return $this->signatures($signatures); + } + + /** + * Set the signature method (currently only Plaintext or SHA-MAC1) + * + * @param method (String) Method of signing the transaction (only PLAINTEXT and SHA-MAC1 allowed for now) + * @return OAuthSimple (Object) + */ + public function setSignatureMethod ($method="") + { + if (empty($method)) + { + $method = $this->_default_signature_method; + } + $method = strtoupper($method); + switch($method) + { + case 'PLAINTEXT': + case 'HMAC-SHA1': + $this->_parameters['oauth_signature_method']=$method; + break; + default: + throw new OAuthSimpleException ("Unknown signing method $method specified for OAuthSimple.setSignatureMethod"); + break; + } + + return $this; + } + + /** sign the request + * + * note: all arguments are optional, provided you've set them using the + * other helper functions. + * + * @param args (Array) hash of arguments for the call {action, path, parameters (array), method, signatures (array)} all arguments are optional. + * @return (Array) signed values + */ + public function sign($args=array()) + { + if (!empty($args['action'])) + { + $this->setAction($args['action']); + } + if (!empty($args['path'])) + { + $this->setPath($args['path']); + } + if (!empty($args['method'])) + { + $this->setSignatureMethod($args['method']); + } + if (!empty($args['signatures'])) + { + $this->signatures($args['signatures']); + } + if (empty($args['parameters'])) + { + $args['parameters']=array(); + } + $this->setParameters($args['parameters']); + $normParams = $this->_normalizedParameters(); + $this->_parameters['oauth_signature'] = $this->_generateSignature($normParams); + + return Array ( + 'parameters' => $this->_parameters, + 'signature' => self::_oauthEscape($this->_parameters['oauth_signature']), + 'signed_url' => $this->_path . '?' . $this->_normalizedParameters(), + 'header' => $this->getHeaderString(), + 'sbs'=> $this->sbs + ); + } + + /** + * Return a formatted "header" string + * + * NOTE: This doesn't set the "Authorization: " prefix, which is required. + * It's not set because various set header functions prefer different + * ways to do that. + * + * @param args (Array) + * @return $result (String) + */ + public function getHeaderString ($args=array()) + { + if (empty($this->_parameters['oauth_signature'])) + { + $this->sign($args); + } + $result = 'OAuth '; + + foreach ($this->_parameters as $pName => $pValue) + { + if (strpos($pName,'oauth_') !== 0 || $pName == 'oauth_token_secret2') + { + continue; + } + if (is_array($pValue)) + { + foreach ($pValue as $val) + { + $result .= $pName .'="' . self::_oauthEscape($val) . '", '; + } + } + else + { + $result .= $pName . '="' . self::_oauthEscape($pValue) . '", '; + } + } + + return preg_replace('/, $/','',$result); + } + + private function _parseParameterString ($paramString) + { + $elements = explode('&',$paramString); + $result = array(); + foreach ($elements as $element) + { + list ($key,$token) = explode('=',$element); + if ($token) + { + $token = urldecode($token); + } + if (!empty($result[$key])) + { + if (!is_array($result[$key])) + { + $result[$key] = array($result[$key],$token); + } + else + { + array_push($result[$key],$token); + } + } + else + $result[$key]=$token; + } + return $result; + } + + + private static function _oauthEscape($string) + { + if ($string === 0) { return 0; } + if ($string == '0') { return '0'; } + if (strlen($string) == 0) { return ''; } + if (is_array($string)) { + throw new OAuthSimpleException('Array passed to _oauthEscape'); + } + $string = rawurlencode($string); + + $string = str_replace('+','%20',$string); + $string = str_replace('!','%21',$string); + $string = str_replace('*','%2A',$string); + $string = str_replace('\'','%27',$string); + $string = str_replace('(','%28',$string); + $string = str_replace(')','%29',$string); + + return $string; + } + + private function _getNonce($length=5) + { + $result = ''; + $cLength = strlen($this->_nonce_chars); + for ($i=0; $i < $length; $i++) + { + $rnum = rand(0,$cLength); + $result .= substr($this->_nonce_chars,$rnum,1); + } + $result = md5($result); + $this->_parameters['oauth_nonce'] = $result; + + return $result; + } + + private function _getApiKey() + { + if (empty($this->_secrets['consumer_key'])) + { + throw new OAuthSimpleException('No consumer_key set for OAuthSimple'); + } + $this->_parameters['oauth_consumer_key']=$this->_secrets['consumer_key']; + + return $this->_parameters['oauth_consumer_key']; + } + + private function _getAccessToken() + { + if (!isset($this->_secrets['oauth_secret'])) + { + return ''; + } + if (!isset($this->_secrets['oauth_token'])) + { + throw new OAuthSimpleException('No access token (oauth_token) set for OAuthSimple.'); + } + $this->_parameters['oauth_token'] = $this->_secrets['oauth_token']; + + return $this->_parameters['oauth_token']; + } + + private function _getTimeStamp() + { + return $this->_parameters['oauth_timestamp'] = time(); + } + + private function _normalizedParameters() + { + $normalized_keys = array(); + $return_array = array(); + + foreach ( $this->_parameters as $paramName=>$paramValue) { + if (!preg_match('/\w+_secret/',$paramName) OR (strpos($paramValue, '@') !== 0 && !file_exists(substr($paramValue, 1))) ) + { + if (is_array($paramValue)) + { + $normalized_keys[self::_oauthEscape($paramName)] = array(); + foreach($paramValue as $item) + { + array_push($normalized_keys[self::_oauthEscape($paramName)], self::_oauthEscape($item)); + } + } + else + { + $normalized_keys[self::_oauthEscape($paramName)] = self::_oauthEscape($paramValue); + } + } + } + + ksort($normalized_keys); + + foreach($normalized_keys as $key=>$val) + { + if (is_array($val)) + { + sort($val); + foreach($val as $element) + { + array_push($return_array, $key . "=" . $element); + } + } + else + { + array_push($return_array, $key .'='. $val); + } + + } + + return join("&", $return_array); + } + + + private function _generateSignature () + { + $secretKey = ''; + if(isset($this->_secrets['shared_secret'])) + { + $secretKey = self::_oauthEscape($this->_secrets['shared_secret']); + } + + $secretKey .= '&'; + if(isset($this->_secrets['oauth_secret'])) + { + $secretKey .= self::_oauthEscape($this->_secrets['oauth_secret']); + } + + switch($this->_parameters['oauth_signature_method']) + { + case 'PLAINTEXT': + return urlencode($secretKey);; + case 'HMAC-SHA1': + $this->sbs = self::_oauthEscape($this->_action).'&'.self::_oauthEscape($this->_path).'&'.self::_oauthEscape($this->_normalizedParameters()); + + return base64_encode(hash_hmac('sha1',$this->sbs,$secretKey,TRUE)); + default: + throw new OAuthSimpleException('Unknown signature method for OAuthSimple'); + break; + } + } +} + +class OAuthSimpleException extends Exception { + + public function __construct($err, $isDebug = FALSE) + { + self::log_error($err); + if ($isDebug) + { + self::display_error($err, TRUE); + } + } + + public static function log_error($err) + { + error_log($err, 0); + } + + public static function display_error($err, $kill = FALSE) + { + print_r($err); + if ($kill === FALSE) + { + die(); + } + } +} diff --git a/DropBoxPhp/sample-form.php b/DropBoxPhp/sample-form.php new file mode 100644 index 0000000..c439f63 --- /dev/null +++ b/DropBoxPhp/sample-form.php @@ -0,0 +1,85 @@ + "ft0zodv89xx804e", + 'app_secret' => "ut43sn7m9wufy3s", + 'app_full_access' => true, +),'it'); + +handle_dropbox_auth($dropbox); // see below + +// if there is no upload, show the form +if(empty($_FILES['the_upload'])) { +?> +
+

+ + +

+

+
+"; + echo "\r\n\r\nUploading $upload_name:\r\n"; + $meta = $dropbox->UploadFile($_FILES["the_upload"]["tmp_name"], $upload_name); + print_r($meta); + echo "\r\n done!"; + echo ""; +} + + +// ================================================================================ +// store_token, load_token, delete_token are SAMPLE functions! please replace with your own! +function store_token($token, $name) +{ + file_put_contents("tokens/$name.token", serialize($token)); +} + +function load_token($name) +{ + if(!file_exists("tokens/$name.token")) return null; + return @unserialize(@file_get_contents("tokens/$name.token")); +} + +function delete_token($name) +{ + @unlink("tokens/$name.token"); +} +// ================================================================================ + +function handle_dropbox_auth($dropbox) +{ + // first try to load existing access token + $access_token = load_token("access"); + if(!empty($access_token)) { + $dropbox->SetAccessToken($access_token); + } + elseif(!empty($_GET['auth_callback'])) // are we coming from dropbox's auth page? + { + // then load our previosly created request token + $request_token = load_token($_GET['oauth_token']); + if(empty($request_token)) die('Request token not found!'); + + // get & store access token, the request token is not needed anymore + $access_token = $dropbox->GetAccessToken($request_token); + store_token($access_token, "access"); + delete_token($_GET['oauth_token']); + } + + // checks if access token is required + if(!$dropbox->IsAuthorized()) + { + // redirect user to dropbox auth page + $return_url = "http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."?auth_callback=1"; + $auth_url = $dropbox->BuildAuthorizeUrl($return_url); + $request_token = $dropbox->GetRequestToken(); + store_token($request_token, $request_token['t']); + die("Authentication required. Click here."); + } +} \ No newline at end of file diff --git a/DropBoxPhp/sample.php b/DropBoxPhp/sample.php new file mode 100644 index 0000000..393023b --- /dev/null +++ b/DropBoxPhp/sample.php @@ -0,0 +1,133 @@ + + * @copyright Fabian Schlieper 2012 + * @version 1.1 + * @license See license.txt + * + */ + + +// these 2 lines are just to enable error reporting and disable output buffering (don't include this in you application!) +error_reporting(E_ALL); +enable_implicit_flush(); +// -- end of unneeded stuff + +// if there are many files in your Dropbox it can take some time, so disable the max. execution time +set_time_limit(0); + +require_once("DropboxClient.php"); + +// you have to create an app at https://www.dropbox.com/developers/apps and enter details below: +$dropbox = new DropboxClient(array( + 'app_key' => "ft0zodv89xx804e", + 'app_secret' => "ut43sn7m9wufy3s", + 'app_full_access' => true, +),'it'); + + +// first try to load existing access token +$access_token = load_token("access"); +if(!empty($access_token)) { + $dropbox->SetAccessToken($access_token); + echo "loaded access token:"; + print_r($access_token); +} +elseif(!empty($_GET['auth_callback'])) // are we coming from dropbox's auth page? +{ + // then load our previosly created request token + $request_token = load_token($_GET['oauth_token']); + if(empty($request_token)) die('Request token not found!'); + + // get & store access token, the request token is not needed anymore + $access_token = $dropbox->GetAccessToken($request_token); + store_token($access_token, "access"); + delete_token($_GET['oauth_token']); +} + +// checks if access token is required +if(!$dropbox->IsAuthorized()) +{ + // redirect user to dropbox auth page + $return_url = "http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."?auth_callback=1"; + $auth_url = $dropbox->BuildAuthorizeUrl($return_url); + $request_token = $dropbox->GetRequestToken(); + store_token($request_token, $request_token['t']); + die("Authentication required. Click here."); +} + +echo "
";
+echo "Account:\r\n";
+print_r($dropbox->GetAccountInfo());
+
+$files = $dropbox->GetFiles("",false);
+
+echo "\r\n\r\nFiles:\r\n";
+print_r(array_keys($files));
+
+if(!empty($files)) {
+	$file = reset($files);
+	$test_file = "test_download_".basename($file->path);
+	
+	echo "\r\n\r\nMeta data of $file->path:\r\n";
+	print_r($dropbox->GetMetadata($file->path));
+	
+	echo "\r\n\r\nDownloading $file->path:\r\n";
+	print_r($dropbox->DownloadFile($file, $test_file));
+		
+	echo "\r\n\r\nUploading $test_file:\r\n";
+	print_r($dropbox->UploadFile($test_file));
+	echo "\r\n done!";	
+	
+	echo "\r\n\r\nRevisions of $test_file:\r\n";	
+	print_r($dropbox->GetRevisions($test_file));
+}
+	
+echo "\r\n\r\nSearching for JPG files:\r\n";	
+$jpg_files = $dropbox->Search("/", ".jpg", 5);
+if(empty($jpg_files))
+	echo "Nothing found.";
+else {
+	print_r($jpg_files);
+	$jpg_file = reset($jpg_files);
+
+	echo "\r\n\r\nThumbnail of $jpg_file->path:\r\n";	
+	$img_data = base64_encode($dropbox->GetThumbnail($jpg_file->path));
+	echo "\"Generating";
+}
+
+
+function store_token($token, $name)
+{
+	if(!file_put_contents("tokens/$name.token", serialize($token)))
+		die('
Could not store token! Make sure that the directory `tokens` exists and is writable!'); +} + +function load_token($name) +{ + if(!file_exists("tokens/$name.token")) return null; + return @unserialize(@file_get_contents("tokens/$name.token")); +} + +function delete_token($name) +{ + @unlink("tokens/$name.token"); +} + + + + + +function enable_implicit_flush() +{ + @apache_setenv('no-gzip', 1); + @ini_set('zlib.output_compression', 0); + @ini_set('implicit_flush', 1); + for ($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); } + ob_implicit_flush(1); + echo ""; +} \ No newline at end of file diff --git a/DropBoxPhp/test_download_Apps b/DropBoxPhp/test_download_Apps new file mode 100644 index 0000000..d538cda --- /dev/null +++ b/DropBoxPhp/test_download_Apps @@ -0,0 +1 @@ +{"error": "File not found"} \ No newline at end of file diff --git a/DropBoxPhp/tokens/access.token b/DropBoxPhp/tokens/access.token new file mode 100644 index 0000000..42b3ffc --- /dev/null +++ b/DropBoxPhp/tokens/access.token @@ -0,0 +1 @@ +a:2:{s:1:"t";s:16:"2lfmugdr7rp3yp2q";s:1:"s";s:15:"i3nrl13aduhhufw";} \ No newline at end of file diff --git a/MySqlClass.php b/MySqlClass.php index 26eebe3..663a5fc 100644 --- a/MySqlClass.php +++ b/MySqlClass.php @@ -1,89 +1,87 @@ -attiva) - { - $this->connessione = mysql_connect($this->nomehost,$this->nomeuser,$this->password); - if ($this->connessione == FALSE) - die(mysql_error()); - mysql_select_db($this->mydb, $this->connessione) or die ("Errore nella selezione del database. Verificare i parametri nel file config.inc.php"); - $this->attiva = true; - } - else{ - return true; - } - - } - - public function executeQuery($queryStr) - { - $this->connetti(); - - if (!$res = mysql_query($queryStr, $this->connessione)) die(mysql_error()); - return true; - return false; - } - - public function insertRecord($queryStr) - { - $this->connetti(); - - if (!$res = mysql_query($queryStr, $this->connessione)) die(mysql_error()); - return mysql_insert_id(); - } - - public function queryToObject($queryStr) - { - $this->connetti(); - - $sth = mysql_query($queryStr, $this->connessione) or die(mysql_error()); - - $rows = array(); - while($r = mysql_fetch_assoc($sth)) { - array_push($rows,array_map('utf8_encode', $r)); - } - mysql_free_result($sth); - return $rows; - } - - // funzione per la chiusura della connessione - public function disconnetti() - { - if($this->attiva) - { - if(mysql_close($this->connessione)) - { - $this->attiva = false; - return true; - } - else - { - return false; - } - } - } - - public function __destruct() - { - $this->disconnetti(); - } - } +attiva) { + $this->connessione = mysqli_connect($this->nomehost, $this->nomeuser, $this->password); + if ($this->connessione == FALSE) + die(mysqli_error()); + mysqli_select_db($this->connessione, $this->mydb) or die("Errore nella selezione del database. Verificare i parametri nel file config.inc.php"); + $this->attiva = true; + } + else { + return true; + } + } + + public function executeQuery($queryStr) { + $this->connetti(); + + if (!$res = mysqli_query($this->connessione, $queryStr)) + die(mysqli_error()); + return true; + } + + public function insertRecord($queryStr) { + $this->connetti(); + + if (!$res = mysqli_query($this->connessione, $queryStr)) + die(mysqli_error()); + return mysqli_insert_id($this->connessione); + } + + public function queryToObject($queryStr, $encode = true) { + $this->connetti(); + + $sth = mysqli_query($this->connessione, $queryStr) or die(mysqli_error()); + + if($encode){ + $rows = array(); + while ($r = mysqli_fetch_assoc($sth)) { + array_push($rows, array_map('utf8_encode', $r)); + } + mysqli_free_result($sth); + return $rows; + } + else + { + return mysqli_fetch_array($sth); + } + } + + // funzione per la chiusura della connessione + public function disconnetti() { + if ($this->attiva) { + if (mysqli_close($this->connessione)) { + $this->attiva = false; + return true; + } else { + return false; + } + } + } + + public function __destruct() { + $this->disconnetti(); + } + +} + ?> \ No newline at end of file diff --git a/PHPImageWorkshop/Core/Exception/ImageWorkshopLayerException.php b/PHPImageWorkshop/Core/Exception/ImageWorkshopLayerException.php index eac77ca..34c1562 100644 --- a/PHPImageWorkshop/Core/Exception/ImageWorkshopLayerException.php +++ b/PHPImageWorkshop/Core/Exception/ImageWorkshopLayerException.php @@ -1,22 +1,22 @@ -width = imagesx($image); - $this->height = imagesy($image); - $this->image = $image; - $this->layers = $this->layerLevels = $this->layerPositions = array(); - $this->clearStack(); - } - - /** - * Clone method: use it if you want to reuse an existing ImageWorkshop object in another variable - * This is important because img resource var references all the same image in PHP. - * Example: $b = clone $a; (never do $b = $a;) - */ - public function __clone() - { - $this->createNewVarFromBackgroundImage(); - } - - // Superimpose a sublayer - // ========================================================= - - /** - * Add an existing ImageWorkshop sublayer and set it in the stack at a given level - * Return an array containing the generated sublayer id in the stack and its corrected level: - * array("layerLevel" => integer, "id" => integer) - * - * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html - * - * @param integer $layerLevel - * @param ImageWorkshop $layer - * @param integer $positionX - * @param integer $positionY - * @param string $position - * - * @return array - */ - public function addLayer($layerLevel, $layer, $positionX = 0, $positionY = 0, $position = 'LT') - { - return $this->indexLayer($layerLevel, $layer, $positionX, $positionY, $position); - } - - /** - * Add an existing ImageWorkshop sublayer and set it in the stack at the highest level - * Return an array containing the generated sublayer id in the stack and the highest level: - * array("layerLevel" => integer, "id" => integer) - * - * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html - * - * @param ImageWorkshop $layer - * @param integer $positionX - * @param integer $positionY - * @param string $position - * - * @return array - */ - public function addLayerOnTop($layer, $positionX = 0, $positionY = 0, $position = 'LT') - { - return $this->indexLayer($this->highestLayerLevel + 1, $layer, $positionX, $positionY, $position); - } - - /** - * Add an existing ImageWorkshop sublayer and set it in the stack at level 1 - * Return an array containing the generated sublayer id in the stack and level 1: - * array("layerLevel" => integer, "id" => integer) - * - * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html - * - * @param ImageWorkshop $layer - * @param integer $positionX - * @param integer $positionY - * @param string $position - * - * @return array - */ - public function addLayerBelow($layer, $positionX = 0, $positionY = 0, $position = 'LT') - { - return $this->indexLayer(1, $layer, $positionX, $positionY, $position); - } - - // Move a sublayer inside the stack - // ========================================================= - - /** - * Move a sublayer on the top of a group stack - * Return new sublayer level if success or false otherwise - * - * @param integer $layerId - * @return mixed - */ - public function moveTop($layerId) - { - return $this->moveTo($layerId, $this->highestLayerLevel, false); - } - - /** - * Move a sublayer to the level 1 of a group stack - * Return new sublayer level if success or false otherwise - * - * @param integer $layerId - * @param integer $level - * - * @return mixed - */ - public function moveBottom($layerId) - { - return $this->moveTo($layerId, 1, true); - } - - /** - * Move a sublayer to the level $level of a group stack - * Return new sublayer level if success or false if layer isn't found - * - * Set $insertUnderTargetedLayer true if you want to move the sublayer under the other sublayer at the targeted level, - * or false to insert it on the top of the other sublayer at the targeted level - * - * @param integer $layerId - * @param integer $level - * @param boolean $insertUnderTargetedLayer - * - * @return mixed - */ - public function moveTo($layerId, $level, $insertUnderTargetedLayer = true) - { - // if the sublayer exists in stack - if ($this->isLayerInIndex($layerId)) { - - $layerOldLevel = $this->getLayerLevel($layerId); - - if ($level < 1) { - $level = 1; - $insertUnderTargetedLayer = true; - } - - if ($level > $this->highestLayerLevel) { - - $level = $this->highestLayerLevel; - $insertUnderTargetedLayer = false; - } - - // Not the same level than the current level - if ($layerOldLevel != $level) { - - $isUnderAndNewLevelHigher = $isUnderAndNewLevelLower = $isOnTopAndNewLevelHigher = $isOnTopAndNewLevelLower = false; - - if ($insertUnderTargetedLayer) { // Under level - - if ($level > $layerOldLevel) { // new level higher - - $incrementorStartingValue = $layerOldLevel; - $stopLoopWhenSmallerThan = $level; - $isUnderAndNewLevelHigher = true; - - } else { // new level lower - - $incrementorStartingValue = $level; - $stopLoopWhenSmallerThan = $layerOldLevel; - $isUnderAndNewLevelLower = true; - } - - } else { // on the top - - if ($level > $layerOldLevel) { // new level higher - - $incrementorStartingValue = $layerOldLevel; - $stopLoopWhenSmallerThan = $level; - $isOnTopAndNewLevelHigher = true; - - } else { // new level lower - - $incrementorStartingValue = $level; - $stopLoopWhenSmallerThan = $layerOldLevel; - $isOnTopAndNewLevelLower = true; - } - } - - ksort($this->layerLevels); - $layerLevelsTmp = $this->layerLevels; - - if ($isOnTopAndNewLevelLower) { - $level++; - } - - for ($i = $incrementorStartingValue; $i < $stopLoopWhenSmallerThan; $i++) { - - if ($isUnderAndNewLevelHigher || $isOnTopAndNewLevelHigher) { - - $this->layerLevels[$i] = $layerLevelsTmp[$i + 1]; - - } else { - - $this->layerLevels[$i + 1] = $layerLevelsTmp[$i]; - } - } - - unset($layerLevelsTmp); - - if ($isUnderAndNewLevelHigher) { - $level--; - } - - $this->layerLevels[$level] = $layerId; - - return $level; - - } else { - return $level; - } - } - - return false; - } - - /** - * Move up a sublayer in the stack (level +1) - * Return new sublayer level if success, false otherwise - * - * @param integer $layerId - * - * @return mixed - */ - public function moveUp($layerId) - { - if ($this->isLayerInIndex($layerId)) { // if the sublayer exists in the stack - $layerOldLevel = $this->getLayerLevel($layerId); - return $this->moveTo($layerId, $layerOldLevel + 1, false); - } - - return false; - } - - /** - * Move down a sublayer in the stack (level -1) - * Return new sublayer level if success, false otherwise - * - * @param integer $layerId - * - * @return mixed - */ - public function moveDown($layerId) - { - if ($this->isLayerInIndex($layerId)) { // if the sublayer exists in the stack - $layerOldLevel = $this->getLayerLevel($layerId); - return $this->moveTo($layerId, $layerOldLevel - 1, true); - } - - return false; - } - - // Merge layers - // ========================================================= - - /** - * Merge a sublayer with another sublayer below it in the stack - * Note: the result layer will conserve the given id - * Return true if success or false if layer isn't found or doesn't have a layer under it in the stack - * - * @param integer $layerId - * - * @return boolean - */ - public function mergeDown($layerId) - { - // if the layer exists in document - if ($this->isLayerInIndex($layerId)) { - - $layerLevel = $this->getLayerLevel($layerId); - $layerPositions = $this->getLayerPositions($layerId); - $layer = $this->getLayer($layerId); - $layerWidth = $layer->getWidth(); - $layerHeight = $layer->getHeight(); - $layerPositionX = $this->layerPositions[$layerId]['x']; - $layerPositionY = $this->layerPositions[$layerId]['y']; - - if ($layerLevel > 1) { - - $underLayerId = $this->layerLevels[$layerLevel - 1]; - $underLayer = $this->getLayer($underLayerId); - $underLayerWidth = $underLayer->getWidth(); - $underLayerHeight = $underLayer->getHeight(); - $underLayerPositionX = $this->layerPositions[$underLayerId]['x']; - $underLayerPositionY = $this->layerPositions[$underLayerId]['y']; - - $totalWidthLayer = $layerWidth + $layerPositionX; - $totalHeightLayer = $layerHeight + $layerPositionY; - - $totalWidthUnderLayer = $underLayerWidth + $underLayerPositionX; - $totalHeightUnderLayer = $underLayerHeight + $underLayerPositionY; - - $minLayerPositionX = $layerPositionX; - - if ($layerPositionX > $underLayerPositionX) { - $minLayerPositionX = $underLayerPositionX; - } - - $minLayerPositionY = $layerPositionY; - - if ($layerPositionY > $underLayerPositionY) { - $minLayerPositionY = $underLayerPositionY; - } - - if ($totalWidthLayer > $totalWidthUnderLayer) { - $layerTmpWidth = $totalWidthLayer - $minLayerPositionX; - } else { - $layerTmpWidth = $totalWidthUnderLayer - $minLayerPositionX; - } - - if ($totalHeightLayer > $totalHeightUnderLayer) { - $layerTmpHeight = $totalHeightLayer - $minLayerPositionY; - } else { - $layerTmpHeight = $totalHeightUnderLayer - $minLayerPositionY; - } - - $layerTmp = ImageWorkshop::initVirginLayer($layerTmpWidth, $layerTmpHeight); - - $layerTmp->addLayer(1, $underLayer, $underLayerPositionX - $minLayerPositionX, $underLayerPositionY - $minLayerPositionY); - $layerTmp->addLayer(2, $layer, $layerPositionX - $minLayerPositionX, $layerPositionY - $minLayerPositionY); - - // Update layers - $layerTmp->mergeAll(); - $this->layers[$underLayerId] = clone $layerTmp; - $this->changePosition($underLayerId, $minLayerPositionX, $minLayerPositionX); - - } else { - - $layerTmp = ImageWorkshop::initFromResourceVar($this->image); - $layerTmp->addLayer(1, $layer, $layerPositionX, $layerPositionY); - - $this->image = $layerTmp->getResult(); // Update background image - } - - unset($layerTmp); - $this->remove($layerId); // Remove the merged layer from the stack - - return true; - } - - return false; - } - - /** - * Merge sublayers in the stack on the layer background - */ - public function mergeAll() - { - $this->image = $this->getResult(); - $this->clearStack(); - } - - /** - * Paste an image on the layer - * You can specify the position left (in pixels) and the position top (in pixels) of the added image relatives to the layer - * Otherwise, it will be set at 0 and 0 - * - * @param string $unit Use one of `UNIT_*` constants, "UNIT_PIXEL" by default - * @param resource $image - * @param integer $positionX - * @param integer $positionY - */ - public function pasteImage($unit = self::UNIT_PIXEL, $image, $positionX = 0, $positionY = 0) - { - if ($unit == self::UNIT_PERCENT) { - - $positionX = round(($positionX / 100) * $this->width); - $positionY = round(($positionY / 100) * $this->height); - } - - imagecopy($this->image, $image, $positionX, $positionY, 0, 0, $image->getWidth(), $image->getHeight()); - } - - // Change sublayer positions - // ========================================================= - - /** - * Change the position of a sublayer for new positions - * - * @param integer $layerId - * @param integer $newPosX - * @param integer $newPosY - * - * @return boolean - */ - public function changePosition($layerId, $newPosX = null, $newPosY = null) - { - // if the sublayer exists in the stack - if ($this->isLayerInIndex($layerId)) { - - if ($newPosX !== null) { - $this->layerPositions[$layerId]['x'] = $newPosX; - } - - if ($newPosY !== null) { - $this->layerPositions[$layerId]['y'] = $newPosY; - } - - return true; - } - - return false; - } - - /** - * Apply a translation on a sublayer that change its positions - * - * @param integer $layerId - * @param integer $addedPosX - * @param integer $addedPosY - * - * @return mixed (array of new positions or false if fail) - */ - public function applyTranslation($layerId, $addedPosX = null, $addedPosY = null) - { - // if the sublayer exists in the stack - if ($this->isLayerInIndex($layerId)) { - - if ($addedPosX !== null) { - $this->layerPositions[$layerId]['x'] += $addedPosX; - } - - if ($addedPosY !== null) { - $this->layerPositions[$layerId]['y'] += $addedPosY; - } - - return $this->layerPositions[$layerId]; - } - - return false; - } - - // Removing sublayers - // ========================================================= - - /** - * Delete a layer (return true if success, false if no sublayer is found) - * - * @param integer $layerId - * - * @return boolean - */ - public function remove($layerId) - { - // if the layer exists in document - if ($this->isLayerInIndex($layerId)) { - - $layerToDeleteLevel = $this->getLayerLevel($layerId); - - // delete - $this->layers[$layerId]->delete(); - unset($this->layers[$layerId]); - unset($this->layerLevels[$layerToDeleteLevel]); - unset($this->layerPositions[$layerId]); - - // One or plural layers are sub of the deleted layer - if (array_key_exists(($layerToDeleteLevel + 1), $this->layerLevels)) { - - ksort($this->layerLevels); - - $layerLevelsTmp = $this->layerLevels; - - $maxOldestLevel = 1; - foreach ($layerLevelsTmp as $levelTmp => $layerIdTmp) { - - if ($levelTmp > $layerToDeleteLevel) { - $this->layerLevels[($levelTmp - 1)] = $layerIdTmp; - } - - $maxOldestLevel++; - } - unset($layerLevelsTmp); - unset($this->layerLevels[$maxOldestLevel]); - } - - $this->highestLayerLevel--; - - return true; - } - - return false; - } - - /** - * Reset the layer stack - * - * @boolean $deleteSubImgVar Delete sublayers image resource var - */ - public function clearStack($deleteSubImgVar = true) - { - if ($deleteSubImgVar) { - foreach ($this->layers as $layer) { - $layer->delete(); - } - } - - unset($this->layers); - unset($this->layerLevels); - unset($this->layerPositions); - - $this->lastLayerId = 0; - $this->layers = array(); - $this->layerLevels = array(); - $this->layerPositions = array(); - $this->highestLayerLevel = 0; - } - - // Perform an action - // ========================================================= - - /** - * Resize the layer by specifying pixel - * - * @param integer $newWidth - * @param integer $newHeight - * @param boolean $converseProportion - * @param integer $positionX - * @param integer $positionY - * @param string $position - * - * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html - * - * $positionX, $positionY, $position can be ignored unless you choose a new width AND a new height AND to conserve proportion. - */ - public function resizeInPixel($newWidth = null, $newHeight = null, $converseProportion = false, $positionX = 0, $positionY = 0, $position = 'MM') - { - $this->resize(self::UNIT_PIXEL, $newWidth, $newHeight, $converseProportion, $positionX, $positionY, $position); - } - - /** - * Resize the layer by specifying a percent - * - * @param float $percentWidth - * @param float $percentHeight - * @param boolean $converseProportion - * @param integer $positionX - * @param integer $positionY - * @param string $position - * - * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html - * - * $positionX, $positionY, $position can be ignored unless you choose a new width AND a new height AND to conserve proportion. - */ - public function resizeInPercent($percentWidth = null, $percentHeight = null, $converseProportion = false, $positionX = 0, $positionY = 0, $position = 'MM') - { - $this->resize(self::UNIT_PERCENT, $percentWidth, $percentHeight, $converseProportion, $positionX, $positionY, $position); - } - - /** - * Resize the layer to fit a bounding box by specifying pixel - * - * @param integer $width - * @param integer $height - * @param boolean $converseProportion - */ - public function resizeToFit($width, $height, $converseProportion = false) - { - if ($this->getWidth() <= $width && $this->getHeight() <= $height) { - return; - } - - if (!$converseProportion) { - $width = min($width, $this->getWidth()); - $height = min($height, $this->getHeight()); - } - - $this->resize(self::UNIT_PIXEL, $width, $height, $converseProportion ? 2 : false); - } - - /** - * Resize the layer - * - * @param string $unit Use one of `UNIT_*` constants, "UNIT_PIXEL" by default - * @param mixed $newWidth (integer or float) - * @param mixed $newHeight (integer or float) - * @param boolean $converseProportion - * @param mixed $positionX (integer or float) - * @param mixed $positionY (integer or float) - * @param string $position - * - * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html - * - * $positionX, $positionY, $position can be ignored unless you choose a new width AND a new height AND to conserve proportion. - */ - public function resize($unit = self::UNIT_PIXEL, $newWidth = null, $newHeight = null, $converseProportion = false, $positionX = 0, $positionY = 0, $position = 'MM') - { - if (is_numeric($newWidth) || is_numeric($newHeight)) { - - if ($unit == self::UNIT_PERCENT) { - - if ($newWidth) { - $newWidth = round(($newWidth / 100) * $this->width); - } - - if ($newHeight) { - $newHeight = round(($newHeight / 100) * $this->height); - } - } - - if (is_numeric($newWidth) && $newWidth <= 0) { - $newWidth = 1; - } - - if (is_numeric($newHeight) && $newHeight <= 0) { - $newHeight = 1; - } - - if ($converseProportion) { // Proportion are conserved - - if ($newWidth && $newHeight) { // Proportions + $newWidth + $newHeight - - if ($this->getWidth() > $this->getHeight()) { - - $this->resizeInPixel($newWidth, null, true); - - if ($this->getHeight() > $newHeight) { - $this->resizeInPixel(null, $newHeight, true); - } - - } else { - - $this->resizeInPixel(null, $newHeight, true); - - if ($this->getWidth() > $newWidth) { - $this->resizeInPixel($newWidth, null, true); - } - } - - if ($converseProportion !== 2 && ($this->getWidth() != $newWidth || $this->getHeight() != $newHeight)) { - - $layerTmp = ImageWorkshop::initVirginLayer($newWidth, $newHeight); - - $layerTmp->addLayer(1, $this, $positionX, $positionY, $position); - - // Reset part of stack - - unset($this->image); - unset($this->layerLevels); - unset($this->layerPositions); - unset($this->layers); - - // Update current object - - $this->width = $layerTmp->getWidth(); - $this->height = $layerTmp->getHeight(); - $this->layerLevels = $layerTmp->layers[1]->getLayerLevels(); - $this->layerPositions = $layerTmp->layers[1]->getLayerPositions(); - $this->layers = $layerTmp->layers[1]->getLayers(); - $this->lastLayerId = $layerTmp->layers[1]->getLastLayerId(); - $this->highestLayerLevel = $layerTmp->layers[1]->getHighestLayerLevel(); - - $translations = $layerTmp->getLayerPositions(1); - - foreach ($this->layers as $id => $layer) { - $this->applyTranslation($id, $translations['x'], $translations['y']); - } - - $layerTmp->layers[1]->clearStack(false); - $this->image = $layerTmp->getResult(); - unset($layerTmp); - } - - return; - - } elseif ($newWidth) { - - $widthResizePercent = $newWidth / ($this->width / 100); - $newHeight = round(($widthResizePercent / 100) * $this->height); - $heightResizePercent = $widthResizePercent; - - } elseif ($newHeight) { - - $heightResizePercent = $newHeight / ($this->height / 100); - $newWidth = round(($heightResizePercent / 100) * $this->width); - $widthResizePercent = $heightResizePercent; - } - - } elseif (($newWidth && !$newHeight) || (!$newWidth && $newHeight)) { // New width OR new height is given - - if ($newWidth) { - - $widthResizePercent = $newWidth / ($this->width / 100); - $heightResizePercent = 100; - $newHeight = $this->height; - - } else { - - $heightResizePercent = $newHeight / ($this->height / 100); - $widthResizePercent = 100; - $newWidth = $this->width; - } - - } else { // New width AND new height are given - - $widthResizePercent = $newWidth / ($this->width / 100); - $heightResizePercent = $newHeight / ($this->height / 100); - } - - // Update the layer positions in the stack - - foreach ($this->layerPositions as $layerId => $layerPosition) { - - $newPosX = round(($widthResizePercent / 100) * $layerPosition['x']); - $newPosY = round(($heightResizePercent / 100) * $layerPosition['y']); - - $this->changePosition($layerId, $newPosX, $newPosY); - } - - // Resize layers in the stack - - $layers = $this->layers; - - foreach ($layers as $key => $layer) { - $layer->resizeInPercent($widthResizePercent, $heightResizePercent); - $this->layers[$key] = $layer; - } - - $this->resizeBackground($newWidth, $newHeight); // Resize the layer - } - } - - /** - * Resize the layer by its largest side by specifying pixel - * - * @param integer $newLargestSideWidth - * @param boolean $converseProportion - */ - public function resizeByLargestSideInPixel($newLargestSideWidth, $converseProportion = false) - { - $this->resizeByLargestSide(self::UNIT_PIXEL, $newLargestSideWidth, $converseProportion); - } - - /** - * Resize the layer by its largest side by specifying percent - * - * @param integer $newLargestSideWidth percent - * @param boolean $converseProportion - */ - public function resizeByLargestSideInPercent($newLargestSideWidth, $converseProportion = false) - { - $this->resizeByLargestSide(self::UNIT_PERCENT, $newLargestSideWidth, $converseProportion); - } - - /** - * Resize the layer by its largest side - * - * @param string $unit - * @param integer $newLargestSideWidth percent - * @param boolean $converseProportion - */ - public function resizeByLargestSide($unit = self::UNIT_PIXEL, $newLargestSideWidth, $converseProportion = false) - { - if ($unit == self::UNIT_PERCENT) { - $newLargestSideWidth = round(($newLargestSideWidth / 100) * $this->getLargestSideWidth()); - } - - if ($this->getWidth() > $this->getHeight()) { - $this->resizeInPixel($newLargestSideWidth, null, $converseProportion); - } else { - $this->resizeInPixel(null, $newLargestSideWidth, $converseProportion); - } - } - - /** - * Resize the layer by its narrow side by specifying pixel - * - * @param integer $newNarrowSideWidth - * @param boolean $converseProportion - */ - public function resizeByNarrowSideInPixel($newNarrowSideWidth, $converseProportion = false) - { - $this->resizeByNarrowSide(self::UNIT_PIXEL, $newNarrowSideWidth, $converseProportion); - } - - /** - * Resize the layer by its narrow side by specifying percent - * - * @param integer $newNarrowSideWidth percent - * @param boolean $converseProportion - */ - public function resizeByNarrowSideInPercent($newNarrowSideWidth, $converseProportion = false) - { - $this->resizeByNarrowSide(self::UNIT_PERCENT, $newNarrowSideWidth, $converseProportion); - } - - /** - * Resize the layer by its narrow side - * - * @param string $unit - * @param integer $newNarrowSideWidth - * @param boolean $converseProportion - */ - public function resizeByNarrowSide($unit = self::UNIT_PIXEL, $newNarrowSideWidth, $converseProportion = false) - { - if ($unit == self::UNIT_PERCENT) { - $newNarrowSideWidth = round(($newNarrowSideWidth / 100) * $this->getNarrowSideWidth()); - } - - if ($this->getWidth() < $this->getHeight()) { - $this->resizeInPixel($newNarrowSideWidth, null, $converseProportion); - } else { - $this->resizeInPixel(null, $newNarrowSideWidth, $converseProportion); - } - } - - /** - * Crop the document by specifying pixels - * - * $backgroundColor: can be set transparent (The script will be longer to execute) - * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html - * - * @param integer $width - * @param integer $height - * @param integer $positionX - * @param integer $positionY - * @param string $position - */ - public function cropInPixel($width = 0, $height = 0, $positionX = 0, $positionY = 0, $position = 'LT') - { - $this->crop(self::UNIT_PIXEL, $width, $height, $positionX, $positionY, $position); - } - - /** - * Crop the document by specifying percent - * - * $backgroundColor can be set transparent (but script could be long to execute) - * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html - * - * @param float $percentWidth - * @param float $percentHeight - * @param float $positionXPercent - * @param float $positionYPercent - * @param string $position - */ - public function cropInPercent($percentWidth = 0, $percentHeight = 0, $positionXPercent = 0, $positionYPercent = 0, $position = 'LT') - { - $this->crop(self::UNIT_PERCENT, $percentWidth, $percentHeight, $positionXPercent, $positionYPercent, $position); - } - - /** - * Crop the document - * - * $backgroundColor can be set transparent (but script could be long to execute) - * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html - * - * @param string $unit - * @param mixed $width (integer or float) - * @param mixed $height (integer or float) - * @param mixed $positionX (integer or float) - * @param mixed $positionY (integer or float) - * @param string $position - */ - public function crop($unit = self::UNIT_PIXEL, $width = 0, $height = 0, $positionX = 0, $positionY = 0, $position = 'LT') - { - if ($width < 0 || $height < 0) { - throw new ImageWorkshopLayerException('You can\'t use negative $width or $height for "'.__METHOD__.'" method.', static::ERROR_NEGATIVE_NUMBER_USED); - } - - if ($unit == self::UNIT_PERCENT) { - - $width = round(($width / 100) * $this->width); - $height = round(($height / 100) * $this->height); - - $positionX = round(($positionX / 100) * $this->width); - $positionY = round(($positionY / 100) * $this->height); - } - - if (($width != $this->width || $positionX == 0) || ($height != $this->height || $positionY == 0)) { - - if ($width == 0) { - $width = 1; - } - - if ($height == 0) { - $height = 1; - } - - $layerTmp = ImageWorkshop::initVirginLayer($width, $height); - $layerClone = ImageWorkshop::initVirginLayer($this->width, $this->height); - - imagedestroy($layerClone->image); - $layerClone->image = $this->image; - - $layerTmp->addLayer(1, $layerClone, -$positionX, -$positionY, $position); - - $newPos = $layerTmp->getLayerPositions(); - $layerNewPosX = $newPos[1]['x']; - $layerNewPosY = $newPos[1]['y']; - - // update the layer - $this->width = $layerTmp->getWidth(); - $this->height = $layerTmp->getHeight(); - $this->image = $layerTmp->getResult(); - unset($layerTmp); - unset($layerClone); - - $this->updateLayerPositionsAfterCropping($layerNewPosX, $layerNewPosY); - } - } - - /** - * Crop the document to a specific aspect ratio by specifying a shift in pixel - * - * $backgroundColor: can be set transparent (The script will be longer to execute) - * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html - * - * @param integer $width - * @param integer $height - * @param integer $positionX - * @param integer $positionY - * @param string $position - */ - public function cropToAspectRatioInPixel($width = 0, $height = 0, $positionX = 0, $positionY = 0, $position = 'LT') - { - $this->cropToAspectRatio(self::UNIT_PIXEL, $width, $height, $positionX, $positionY, $position); - } - - /** - * Crop the document to a specific aspect ratio by specifying a shift in percent - * - * $backgroundColor can be set transparent (but script could be long to execute) - * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html - * - * @param integer $width - * @param integer $height - * @param float $positionXPercent - * @param float $positionYPercent - * @param string $position - */ - public function cropToAspectRatioInPercent($width = 0, $height = 0, $positionXPercent = 0, $positionYPercent = 0, $position = 'LT') - { - $this->cropToAspectRatio(self::UNIT_PERCENT, $width, $height, $positionXPercent, $positionYPercent, $position); - } - - /** - * Crop the document to a specific aspect ratio - * - * $backgroundColor can be set transparent (but script could be long to execute) - * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html - * - * @param string $unit - * @param integer $width (integer or float) - * @param integer $height (integer or float) - * @param mixed $positionX (integer or float) - * @param mixed $positionY (integer or float) - * @param string $position - */ - public function cropToAspectRatio($unit = self::UNIT_PIXEL, $width = 0, $height = 0, $positionX = 0, $positionY = 0, $position = 'LT') - { - if ($width < 0 || $height < 0) { - throw new ImageWorkshopLayerException('You can\'t use negative $width or $height for "'.__METHOD__.'" method.', static::ERROR_NEGATIVE_NUMBER_USED); - } - - if ($width == 0) { - $width = 1; - } - - if ($height == 0) { - $height = 1; - } - - if ($this->width / $this->height <= $width / $height) { - $newWidth = $this->width; - $newHeight = round($height * ($this->width / $width)); - } else { - $newWidth = round($width * ($this->height / $height)); - $newHeight = $this->height; - } - - if ($unit == self::UNIT_PERCENT) { - $positionX = round(($positionX / 100) * ($this->width - $newWidth)); - $positionY = round(($positionY / 100) * ($this->height - $newHeight)); - } - - $this->cropInPixel($newWidth, $newHeight, $positionX, $positionY, $position); - } - - /** - * Crop the maximum possible from left top ("LT"), "RT"... by specifying a shift in pixel - * - * $backgroundColor can be set transparent (but script could be long to execute) - * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html - * - * @param integer $width - * @param integer $height - * @param integer $positionX - * @param integer $positionY - * @param string $position - */ - public function cropMaximumInPixel($positionX = 0, $positionY = 0, $position = 'LT') - { - $this->cropMaximum(self::UNIT_PIXEL, $positionX, $positionY, $position); - } - - /** - * Crop the maximum possible from left top ("LT"), "RT"... by specifying a shift in percent - * - * $backgroundColor can be set transparent (but script could be long to execute) - * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html - * - * @param integer $width - * @param integer $height - * @param integer $positionXPercent - * @param integer $positionYPercent - * @param string $position - */ - public function cropMaximumInPercent($positionXPercent = 0, $positionYPercent = 0, $position = 'LT') - { - $this->cropMaximum(self::UNIT_PERCENT, $positionXPercent, $positionYPercent, $position); - } - - /** - * Crop the maximum possible from left top - * - * $backgroundColor can be set transparent (but script could be long to execute) - * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html - * - * @param string $unit - * @param integer $width - * @param integer $height - * @param integer $positionX - * @param integer $positionY - * @param string $position - */ - public function cropMaximum($unit = self::UNIT_PIXEL, $positionX = 0, $positionY = 0, $position = 'LT') - { - $narrowSide = $this->getNarrowSideWidth(); - - if ($unit == self::UNIT_PERCENT) { - $positionX = round(($positionX / 100) * $this->width); - $positionY = round(($positionY / 100) * $this->height); - } - - $this->cropInPixel($narrowSide, $narrowSide, $positionX, $positionY, $position); - } - - /** - * Rotate the layer (in degree) - * - * @param float $degrees - */ - public function rotate($degrees) - { - if ($degrees != 0) { - - if ($degrees < -360 || $degrees > 360) { - $degrees = $degrees % 360; - } - - if ($degrees < 0 && $degrees >= -360) { - $degrees = 360 + $degrees; - } - - // Rotate the layer background image - $imageRotated = imagerotate($this->image, -$degrees, -1); - imagealphablending($imageRotated, true); - imagesavealpha($imageRotated, true); - - unset($this->image); - - $this->image = $imageRotated; - - $oldWidth = $this->width; - $oldHeight = $this->height; - - $this->width = imagesx($this->image); - $this->height = imagesy($this->image); - - foreach ($this->layers as $layerId => $layer) { - - $layerSelfOldCenterPosition = array( - 'x' => $layer->width / 2, - 'y' => $layer->height / 2, - ); - - $smallImageCenter = array( - 'x' => $layerSelfOldCenterPosition['x'] + $this->layerPositions[$layerId]['x'], - 'y' => $layerSelfOldCenterPosition['y'] + $this->layerPositions[$layerId]['y'], - ); - - $this->layers[$layerId]->rotate($degrees); - - $ro = sqrt(pow($smallImageCenter['x'], 2) + pow($smallImageCenter['y'], 2)); - - $teta = (acos($smallImageCenter['x'] / $ro)) * 180 / pi(); - - $a = $ro * cos(($teta + $degrees) * pi() / 180); - $b = $ro * sin(($teta + $degrees) * pi() / 180); - - if ($degrees > 0 && $degrees <= 90) { - - $newPositionX = $a - ($this->layers[$layerId]->width / 2) + $oldHeight * sin(($degrees * pi()) / 180); - $newPositionY = $b - ($this->layers[$layerId]->height / 2); - - } elseif ($degrees > 90 && $degrees <= 180) { - - $newPositionX = $a - ($this->layers[$layerId]->width / 2) + $this->width; - $newPositionY = $b - ($this->layers[$layerId]->height / 2) + $oldHeight * (-cos(($degrees) * pi() / 180)); - - } elseif ($degrees > 180 && $degrees <= 270) { - - $newPositionX = $a - ($this->layers[$layerId]->width / 2) + $oldWidth * (-cos(($degrees) * pi() / 180)); - $newPositionY = $b - ($this->layers[$layerId]->height / 2) + $this->height; - - } else { - - $newPositionX = $a - ($this->layers[$layerId]->width / 2); - $newPositionY = $b - ($this->layers[$layerId]->height / 2) + $oldWidth * (-sin(($degrees) * pi() / 180)); - } - - $this->layerPositions[$layerId] = array( - 'x' => $newPositionX, - 'y' => $newPositionY, - ); - } - } - } - - /** - * Change the opacity of the layer - * $recursive: apply it on sublayers - * - * @param integer $opacity - * @param boolean $recursive - */ - public function opacity($opacity, $recursive = true) - { - if ($recursive) { - - $layers = $this->layers; - - foreach ($layers as $key => $layer) { - $layer->opacity($opacity, true); - $this->layers[$key] = $layer; - } - } - - $transparentImage = ImageWorkshopLib::generateImage($this->getWidth(), $this->getHeight()); - - ImageWorkshopLib::imageCopyMergeAlpha($transparentImage, $this->image, 0, 0, 0, 0, $this->getWidth(), $this->getHeight(), $opacity); - - unset($this->image); - $this->image = $transparentImage; - unset($transparentImage); - } - - /** - * Apply a filter on the layer - * Be careful: some filters can damage transparent images, use it sparingly ! (A good pratice is to use mergeAll on your layer before applying a filter) - * - * @param int $filterType (http://www.php.net/manual/en/function.imagefilter.php) - * @param int $arg1 - * @param int $arg2 - * @param int $arg3 - * @param int $arg4 - * @param boolean $recursive - */ - public function applyFilter($filterType, $arg1 = null, $arg2 = null, $arg3 = null, $arg4 = null, $recursive = false) - { - if ($filterType == IMG_FILTER_COLORIZE) { - imagefilter($this->image, $filterType, $arg1, $arg2, $arg3, $arg4); - } elseif ($filterType == IMG_FILTER_BRIGHTNESS || $filterType == IMG_FILTER_CONTRAST || $filterType == IMG_FILTER_SMOOTH) { - imagefilter($this->image, $filterType, $arg1); - } elseif ($filterType == IMG_FILTER_PIXELATE) { - imagefilter($this->image, $filterType, $arg1, $arg2); - } else { - imagefilter($this->image, $filterType); - } - - if ($recursive) { - - $layers = $this->layers; - - foreach($layers as $layerId => $layer) { - $this->layers[$layerId]->applyFilter($filterType, $arg1, $arg2, $arg3, $arg4, true); - } - } - } - - /** - * Apply horizontal or vertical flip (Transformation) - * - * @param string $type - */ - public function flip($type = 'horizontal') - { - $layers = $this->layers; - - foreach ($layers as $key => $layer) { - - $layer->flip($type); - $this->layers[$key] = $layer; - } - - $temp = ImageWorkshopLib::generateImage($this->width, $this->height); - - if ($type == 'horizontal') { - - imagecopyresampled($temp, $this->image, 0, 0, $this->width - 1, 0, $this->width, $this->height, -$this->width, $this->height); - $this->image = $temp; - - foreach ($this->layerPositions as $layerId => $layerPositions) { - - $this->changePosition($layerId, $this->width - $this->layers[$layerId]->getWidth() - $layerPositions['x'], $layerPositions['y']); - } - - } elseif ($type == 'vertical') { - - imagecopyresampled($temp, $this->image, 0, 0, 0, $this->height - 1, $this->width, $this->height, $this->width, -$this->height); - $this->image = $temp; - - foreach ($this->layerPositions as $layerId => $layerPositions) { - - $this->changePosition($layerId, $layerPositions['x'], $this->height - $this->layers[$layerId]->getHeight() - $layerPositions['y']); - } - } - - unset($temp); - } - - /** - * Add a text on the background image of the layer using a default font registered in GD - * - * @param string $text - * @param integer $font - * @param string $color - * @param integer $positionX - * @param integer $positionY - * @param string $align - */ - public function writeText($text, $font = 1, $color = 'ffffff', $positionX = 0, $positionY = 0, $align = 'horizontal') - { - $RGBTextColor = ImageWorkshopLib::convertHexToRGB($color); - $textColor = imagecolorallocate($this->image, $RGBTextColor['R'], $RGBTextColor['G'], $RGBTextColor['B']); - - if ($align == 'horizontal') { - imagestring($this->image, $font, $positionX, $positionY, $text, $textColor); - } else { - imagestringup($this->image, $font, $positionX, $positionY, $text, $textColor); - } - } - - /** - * Add a text on the background image of the layer using a font localized at $fontPath - * Return the text coordonates - * - * @param string $text - * @param integer $fontPath - * @param integer $fontSize - * @param string $color - * @param integer $positionX - * @param integer $positionY - * @param integer $fontRotation - * - * @return array - */ - public function write($text, $fontPath, $fontSize = 13, $color = 'ffffff', $positionX = 0, $positionY = 0, $fontRotation = 0) - { - if (!file_exists($fontPath)) { - throw new ImageWorkshopLayerException('Can\'t find a font file at this path : "'.$fontPath.'".', static::ERROR_FONT_NOT_FOUND); - } - - $RGBTextColor = ImageWorkshopLib::convertHexToRGB($color); - $textColor = imagecolorallocate($this->image, $RGBTextColor['R'], $RGBTextColor['G'], $RGBTextColor['B']); - - return imagettftext($this->image, $fontSize, $fontRotation, $positionX, $positionY, $textColor, $fontPath, $text); - } - - // Manage the result - // ========================================================= - - /** - * Return a merged resource image - * - * $backgroundColor is really usefull if you want to save a JPG or GIF, because the transparency of the background - * would be remove for a colored background, so you should choose a color like "ffffff" (white) - * - * @param string $backgroundColor - * - * @return resource - */ - public function getResult($backgroundColor = null) - { - $imagesToMerge = array(); - ksort($this->layerLevels); - - foreach ($this->layerLevels as $layerLevel => $layerId) { - - $imagesToMerge[$layerLevel] = $this->layers[$layerId]->getResult(); - - // Layer positions - if ($this->layerPositions[$layerId]['x'] != 0 || $this->layerPositions[$layerId]['y'] != 0) { - - $virginLayoutImageTmp = ImageWorkshopLib::generateImage($this->width, $this->height); - ImageWorkshopLib::mergeTwoImages($virginLayoutImageTmp, $imagesToMerge[$layerLevel], $this->layerPositions[$layerId]['x'], $this->layerPositions[$layerId]['y'], 0, 0); - $imagesToMerge[$layerLevel] = $virginLayoutImageTmp; - unset($virginLayoutImageTmp); - } - } - - $iterator = 1; - $mergedImage = $this->image; - ksort($imagesToMerge); - - foreach ($imagesToMerge as $imageLevel => $image) { - ImageWorkshopLib::mergeTwoImages($mergedImage, $image); - $iterator++; - } - - $opacity = 127; - - if ($backgroundColor && $backgroundColor != 'transparent') { - $opacity = 0; - } - - $backgroundImage = ImageWorkshopLib::generateImage($this->width, $this->height, $backgroundColor, $opacity); - ImageWorkshopLib::mergeTwoImages($backgroundImage, $mergedImage); - $mergedImage = $backgroundImage; - unset($backgroundImage); - - return $mergedImage; - } - - /** - * Save the resulting image at the specified path - * - * $backgroundColor is really usefull if you want to save a JPG or GIF, because the transparency of the background - * would be remove for a colored background, so you should choose a color like "ffffff" (white) - * - * If the file already exists, it will be override ! - * - * $imageQuality is useless for GIF - * - * Ex: $folder = __DIR__."/../web/images/2012" - * $imageName = "butterfly.jpg" - * $createFolders = true - * $imageQuality = 95 - * $backgroundColor = "ffffff" - * - * @param string $folder - * @param string $imageName - * @param boolean $createFolders - * @param string $backgroundColor - * @param integer $imageQuality - * @param boolean $interlace - */ - public function save($folder, $imageName, $createFolders = true, $backgroundColor = null, $imageQuality = 75, $interlace = false) - { - if (!is_file($folder)) { - - if (is_dir($folder) || $createFolders) { - - // Creating the folders if they don't exist - if (!is_dir($folder) && $createFolders) { - $oldUmask = umask(0); - mkdir($folder, 0777, true); - umask($oldUmask); - chmod($folder, 0777); - } - - $extension = explode('.', $imageName); - $extension = strtolower($extension[count($extension) - 1]); - - $filename = $folder.'/'.$imageName; - - if (($extension == 'jpg' || $extension == 'jpeg' || $extension == 'gif') && (!$backgroundColor || $backgroundColor == 'transparent')) { - $backgroundColor = 'ffffff'; - } - - $image = $this->getResult($backgroundColor); - - imageinterlace($image, (int) $interlace); - - if ($extension == 'jpg' || $extension == 'jpeg') { - - imagejpeg($image, $filename, $imageQuality); - unset($image); - - } elseif ($extension == 'gif') { - - imagegif($image, $filename); - unset($image); - - } elseif ($extension == 'png') { - - $imageQuality = $imageQuality / 10; - $imageQuality -= 1; - - imagepng($image, $filename, $imageQuality); - unset($image); - } - } - } - } - - // Checkers - // ========================================================= - - /** - * Check if a sublayer exists in the stack for a given id - * - * @param integer $layerId - * - * @return boolean - */ - public function isLayerInIndex($layerId) - { - if (array_key_exists($layerId, $this->layers)) { - return true; - } - - return false; - } - - // Getter / Setter - // ========================================================= - - /** - * Return the narrow side width of the layer - * - * @return integer - */ - public function getNarrowSideWidth() - { - $narrowSideWidth = $this->getWidth(); - - if ($this->getHeight() < $narrowSideWidth) { - $narrowSideWidth = $this->getHeight(); - } - - return $narrowSideWidth; - } - - /** - * Return the largest side width of the layer - * - * @return integer - */ - public function getLargestSideWidth() - { - $largestSideWidth = $this->getWidth(); - - if ($this->getHeight() > $largestSideWidth) { - $largestSideWidth = $this->getHeight(); - } - - return $largestSideWidth; - } - - /** - * Get the level of a sublayer - * Return sublayer level if success or false if layer isn't found - * - * @param integer $layerId - * - * @return mixed (integer or boolean) - */ - public function getLayerLevel($layerId) - { - if ($this->isLayerInIndex($layerId)) { // if the layer exists in document - return array_search($layerId, $this->layerLevels); - } - - return false; - } - - /** - * Get a sublayer in the stack - * Don't forget to use clone method: $b = clone $a->getLayer(3); - * - * @param integer $layerId - * - * @return ImageWorkshop - */ - public function getLayer($layerId) - { - return $this->layers[$layerId]; - } - - /** - * Getter width - * - * @return integer - */ - public function getWidth() - { - return $this->width; - } - - /** - * Getter height - * - * @return integer - */ - public function getHeight() - { - return $this->height; - } - - /** - * Getter image - * - * @return resource - */ - public function getImage() - { - return $this->image; - } - - /** - * Getter layers - * - * @return array - */ - public function getLayers() - { - return $this->layers; - } - - /** - * Getter layerLevels - * - * @return array - */ - public function getLayerLevels() - { - return $this->layerLevels; - } - - /** - * Getter layerPositions - * - * Get all the positions of the sublayers, - * or when specifying $layerId, get the position of this sublayer - * - * @param integer $layerId - * - * @return mixed (array or boolean) - */ - public function getLayerPositions($layerId = null) - { - if (!$layerId) { - - return $this->layerPositions; - - } elseif ($this->isLayerInIndex($layerId)) { // if the sublayer exists in the stack - - return $this->layerPositions[$layerId]; - } - - return false; - } - - /** - * Getter highestLayerLevel - * - * @return array - */ - public function getHighestLayerLevel() - { - return $this->highestLayerLevel; - } - - /** - * Getter lastLayerId - * - * @return array - */ - public function getLastLayerId() - { - return $this->lastLayerId; - } - - // Internals - // ========================================================= - - /** - * Delete the current object - */ - public function delete() - { - imagedestroy($this->image); - $this->clearStack(); - } - - /** - * Create a new background image var from the old background image var - */ - public function createNewVarFromBackgroundImage() - { - $virginImage = ImageWorkshopLib::generateImage($this->getWidth(), $this->getHeight()); // New background image - - ImageWorkshopLib::mergeTwoImages($virginImage, $this->image, 0, 0, 0, 0); - unset($this->image); - - $this->image = $virginImage; - unset($virginImage); - - $layers = $this->layers; - - foreach($layers as $layerId => $layer) { - $this->layers[$layerId] = clone $this->layers[$layerId]; - } - } - - /** - * Index a sublayer in the layer stack - * Return an array containing the generated sublayer id and its final level: - * array("layerLevel" => integer, "id" => integer) - * - * @param integer $layerLevel - * @param ImageWorkshopLayer $layer - * @param integer $positionX - * @param integer $positionY - * @param string $position - * - * @return array - */ - protected function indexLayer($layerLevel, $layer, $positionX = 0, $positionY = 0, $position) - { - // Choose an id for the added layer - $layerId = $this->lastLayerId + 1; - - // Clone $layer to duplicate image resource var - $layer = clone $layer; - - // Add the layer in the stack - $this->layers[$layerId] = $layer; - - // Add the layer positions in the main layer - $this->layerPositions[$layerId] = ImageWorkshopLib::calculatePositions($this->getWidth(), $this->getHeight(), $layer->getWidth(), $layer->getHeight(), $positionX, $positionY, $position); - - // Update the lastLayerId of the workshop - $this->lastLayerId = $layerId; - - // Add the layer level in the stack - $layerLevel = $this->indexLevelInDocument($layerLevel, $layerId); - - return array( - 'layerLevel' => $layerLevel, - 'id' => $layerId, - ); - } - - /** - * Index a layer level and update the layers levels in the document - * Return the corrected level of the layer - * - * @param integer $layerLevel - * @param integer $layerId - * - * @return integer - */ - protected function indexLevelInDocument($layerLevel, $layerId) - { - if (array_key_exists($layerLevel, $this->layerLevels)) { // Level already exists - - ksort($this->layerLevels); // All layers after this level and the layer which have this level are updated - $layerLevelsTmp = $this->layerLevels; - - foreach ($layerLevelsTmp as $levelTmp => $layerIdTmp) { - if ($levelTmp >= $layerLevel) { - $this->layerLevels[$levelTmp + 1] = $layerIdTmp; - } - } - - unset($layerLevelsTmp); - - } else { // Level isn't taken - if ($this->highestLayerLevel < $layerLevel) { // If given level is too high, proceed adjustement - $layerLevel = $this->highestLayerLevel + 1; - } - } - - $this->layerLevels[$layerLevel] = $layerId; - $this->highestLayerLevel = max(array_flip($this->layerLevels)); // Update $highestLayerLevel - - return $layerLevel; - } - - /** - * Update the positions of layers in the stack after cropping - * - * @param integer $positionX - * @param integer $positionY - */ - public function updateLayerPositionsAfterCropping($positionX, $positionY) - { - foreach ($this->layers as $layerId => $layer) { - - $oldLayerPosX = $this->layerPositions[$layerId]['x']; - $oldLayerPosY = $this->layerPositions[$layerId]['y']; - - $newLayerPosX = $oldLayerPosX + $positionX; - $newLayerPosY = $oldLayerPosY + $positionY; - - $this->changePosition($layerId, $newLayerPosX, $newLayerPosY); - } - } - - /** - * Resize the background of a layer - * - * @param integer $newWidth - * @param integer $newHeight - */ - public function resizeBackground($newWidth, $newHeight) - { - $oldWidth = $this->width; - $oldHeight = $this->height; - - $this->width = $newWidth; - $this->height = $newHeight; - - $virginLayoutImage = ImageWorkshopLib::generateImage($this->width, $this->height); - - imagecopyresampled($virginLayoutImage, $this->image, 0, 0, 0, 0, $this->width, $this->height, $oldWidth, $oldHeight); - - unset($this->image); - $this->image = $virginLayoutImage; - } - - // Deprecated, don't use anymore - // ========================================================= - - /** - * @deprecated - */ - public function resizeInPourcent($percentWidth = null, $percentHeight = null, $converseProportion = false, $positionX = 0, $positionY = 0, $position = 'MM') - { - throw new ImageWorkshopLayerException('Method resizeInPourcent() was renamed resizeInPercent(). Use resizeInPercent() instead.', static::METHOD_DEPRECATED); - } - - /** - * @deprecated - */ - public function resizeByLargestSideInPourcent($newLargestSideWidth, $converseProportion = false) - { - throw new ImageWorkshopLayerException('Method resizeByLargestSideInPourcent() was renamed resizeByLargestSideInPercent(). Use resizeByLargestSideInPercent() instead.', static::METHOD_DEPRECATED); - } - - /** - * @deprecated - */ - public function resizeByNarrowSideInPourcent($newNarrowSideWidth, $converseProportion = false) - { - throw new ImageWorkshopLayerException('Method resizeByNarrowSideInPourcent() was renamed resizeByNarrowSideInPercent(). Use resizeByNarrowSideInPercent() instead.', static::METHOD_DEPRECATED); - } - - /** - * @deprecated - */ - public function cropInPourcent($percentWidth = 0, $percentHeight = 0, $positionXPercent = 0, $positionYPercent = 0, $position = 'LT') - { - throw new ImageWorkshopLayerException('Method cropInPourcent() was renamed cropInPercent(). Use cropInPercent() instead.', static::METHOD_DEPRECATED); - } - - /** - * @deprecated - */ - public function cropMaximumInPourcent($positionXPercent = 0, $positionYPercent = 0, $position = 'LT') - { - throw new ImageWorkshopLayerException('Method cropMaximumInPourcent() was renamed cropMaximumInPercent(). Use cropMaximumInPercent() instead.', static::METHOD_DEPRECATED); - } -} +width = imagesx($image); + $this->height = imagesy($image); + $this->image = $image; + $this->layers = $this->layerLevels = $this->layerPositions = array(); + $this->clearStack(); + } + + /** + * Clone method: use it if you want to reuse an existing ImageWorkshop object in another variable + * This is important because img resource var references all the same image in PHP. + * Example: $b = clone $a; (never do $b = $a;) + */ + public function __clone() + { + $this->createNewVarFromBackgroundImage(); + } + + // Superimpose a sublayer + // ========================================================= + + /** + * Add an existing ImageWorkshop sublayer and set it in the stack at a given level + * Return an array containing the generated sublayer id in the stack and its corrected level: + * array("layerLevel" => integer, "id" => integer) + * + * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html + * + * @param integer $layerLevel + * @param ImageWorkshop $layer + * @param integer $positionX + * @param integer $positionY + * @param string $position + * + * @return array + */ + public function addLayer($layerLevel, $layer, $positionX = 0, $positionY = 0, $position = 'LT') + { + return $this->indexLayer($layerLevel, $layer, $positionX, $positionY, $position); + } + + /** + * Add an existing ImageWorkshop sublayer and set it in the stack at the highest level + * Return an array containing the generated sublayer id in the stack and the highest level: + * array("layerLevel" => integer, "id" => integer) + * + * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html + * + * @param ImageWorkshop $layer + * @param integer $positionX + * @param integer $positionY + * @param string $position + * + * @return array + */ + public function addLayerOnTop($layer, $positionX = 0, $positionY = 0, $position = 'LT') + { + return $this->indexLayer($this->highestLayerLevel + 1, $layer, $positionX, $positionY, $position); + } + + /** + * Add an existing ImageWorkshop sublayer and set it in the stack at level 1 + * Return an array containing the generated sublayer id in the stack and level 1: + * array("layerLevel" => integer, "id" => integer) + * + * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html + * + * @param ImageWorkshop $layer + * @param integer $positionX + * @param integer $positionY + * @param string $position + * + * @return array + */ + public function addLayerBelow($layer, $positionX = 0, $positionY = 0, $position = 'LT') + { + return $this->indexLayer(1, $layer, $positionX, $positionY, $position); + } + + // Move a sublayer inside the stack + // ========================================================= + + /** + * Move a sublayer on the top of a group stack + * Return new sublayer level if success or false otherwise + * + * @param integer $layerId + * @return mixed + */ + public function moveTop($layerId) + { + return $this->moveTo($layerId, $this->highestLayerLevel, false); + } + + /** + * Move a sublayer to the level 1 of a group stack + * Return new sublayer level if success or false otherwise + * + * @param integer $layerId + * @param integer $level + * + * @return mixed + */ + public function moveBottom($layerId) + { + return $this->moveTo($layerId, 1, true); + } + + /** + * Move a sublayer to the level $level of a group stack + * Return new sublayer level if success or false if layer isn't found + * + * Set $insertUnderTargetedLayer true if you want to move the sublayer under the other sublayer at the targeted level, + * or false to insert it on the top of the other sublayer at the targeted level + * + * @param integer $layerId + * @param integer $level + * @param boolean $insertUnderTargetedLayer + * + * @return mixed + */ + public function moveTo($layerId, $level, $insertUnderTargetedLayer = true) + { + // if the sublayer exists in stack + if ($this->isLayerInIndex($layerId)) { + + $layerOldLevel = $this->getLayerLevel($layerId); + + if ($level < 1) { + $level = 1; + $insertUnderTargetedLayer = true; + } + + if ($level > $this->highestLayerLevel) { + + $level = $this->highestLayerLevel; + $insertUnderTargetedLayer = false; + } + + // Not the same level than the current level + if ($layerOldLevel != $level) { + + $isUnderAndNewLevelHigher = $isUnderAndNewLevelLower = $isOnTopAndNewLevelHigher = $isOnTopAndNewLevelLower = false; + + if ($insertUnderTargetedLayer) { // Under level + + if ($level > $layerOldLevel) { // new level higher + + $incrementorStartingValue = $layerOldLevel; + $stopLoopWhenSmallerThan = $level; + $isUnderAndNewLevelHigher = true; + + } else { // new level lower + + $incrementorStartingValue = $level; + $stopLoopWhenSmallerThan = $layerOldLevel; + $isUnderAndNewLevelLower = true; + } + + } else { // on the top + + if ($level > $layerOldLevel) { // new level higher + + $incrementorStartingValue = $layerOldLevel; + $stopLoopWhenSmallerThan = $level; + $isOnTopAndNewLevelHigher = true; + + } else { // new level lower + + $incrementorStartingValue = $level; + $stopLoopWhenSmallerThan = $layerOldLevel; + $isOnTopAndNewLevelLower = true; + } + } + + ksort($this->layerLevels); + $layerLevelsTmp = $this->layerLevels; + + if ($isOnTopAndNewLevelLower) { + $level++; + } + + for ($i = $incrementorStartingValue; $i < $stopLoopWhenSmallerThan; $i++) { + + if ($isUnderAndNewLevelHigher || $isOnTopAndNewLevelHigher) { + + $this->layerLevels[$i] = $layerLevelsTmp[$i + 1]; + + } else { + + $this->layerLevels[$i + 1] = $layerLevelsTmp[$i]; + } + } + + unset($layerLevelsTmp); + + if ($isUnderAndNewLevelHigher) { + $level--; + } + + $this->layerLevels[$level] = $layerId; + + return $level; + + } else { + return $level; + } + } + + return false; + } + + /** + * Move up a sublayer in the stack (level +1) + * Return new sublayer level if success, false otherwise + * + * @param integer $layerId + * + * @return mixed + */ + public function moveUp($layerId) + { + if ($this->isLayerInIndex($layerId)) { // if the sublayer exists in the stack + $layerOldLevel = $this->getLayerLevel($layerId); + return $this->moveTo($layerId, $layerOldLevel + 1, false); + } + + return false; + } + + /** + * Move down a sublayer in the stack (level -1) + * Return new sublayer level if success, false otherwise + * + * @param integer $layerId + * + * @return mixed + */ + public function moveDown($layerId) + { + if ($this->isLayerInIndex($layerId)) { // if the sublayer exists in the stack + $layerOldLevel = $this->getLayerLevel($layerId); + return $this->moveTo($layerId, $layerOldLevel - 1, true); + } + + return false; + } + + // Merge layers + // ========================================================= + + /** + * Merge a sublayer with another sublayer below it in the stack + * Note: the result layer will conserve the given id + * Return true if success or false if layer isn't found or doesn't have a layer under it in the stack + * + * @param integer $layerId + * + * @return boolean + */ + public function mergeDown($layerId) + { + // if the layer exists in document + if ($this->isLayerInIndex($layerId)) { + + $layerLevel = $this->getLayerLevel($layerId); + $layerPositions = $this->getLayerPositions($layerId); + $layer = $this->getLayer($layerId); + $layerWidth = $layer->getWidth(); + $layerHeight = $layer->getHeight(); + $layerPositionX = $this->layerPositions[$layerId]['x']; + $layerPositionY = $this->layerPositions[$layerId]['y']; + + if ($layerLevel > 1) { + + $underLayerId = $this->layerLevels[$layerLevel - 1]; + $underLayer = $this->getLayer($underLayerId); + $underLayerWidth = $underLayer->getWidth(); + $underLayerHeight = $underLayer->getHeight(); + $underLayerPositionX = $this->layerPositions[$underLayerId]['x']; + $underLayerPositionY = $this->layerPositions[$underLayerId]['y']; + + $totalWidthLayer = $layerWidth + $layerPositionX; + $totalHeightLayer = $layerHeight + $layerPositionY; + + $totalWidthUnderLayer = $underLayerWidth + $underLayerPositionX; + $totalHeightUnderLayer = $underLayerHeight + $underLayerPositionY; + + $minLayerPositionX = $layerPositionX; + + if ($layerPositionX > $underLayerPositionX) { + $minLayerPositionX = $underLayerPositionX; + } + + $minLayerPositionY = $layerPositionY; + + if ($layerPositionY > $underLayerPositionY) { + $minLayerPositionY = $underLayerPositionY; + } + + if ($totalWidthLayer > $totalWidthUnderLayer) { + $layerTmpWidth = $totalWidthLayer - $minLayerPositionX; + } else { + $layerTmpWidth = $totalWidthUnderLayer - $minLayerPositionX; + } + + if ($totalHeightLayer > $totalHeightUnderLayer) { + $layerTmpHeight = $totalHeightLayer - $minLayerPositionY; + } else { + $layerTmpHeight = $totalHeightUnderLayer - $minLayerPositionY; + } + + $layerTmp = ImageWorkshop::initVirginLayer($layerTmpWidth, $layerTmpHeight); + + $layerTmp->addLayer(1, $underLayer, $underLayerPositionX - $minLayerPositionX, $underLayerPositionY - $minLayerPositionY); + $layerTmp->addLayer(2, $layer, $layerPositionX - $minLayerPositionX, $layerPositionY - $minLayerPositionY); + + // Update layers + $layerTmp->mergeAll(); + $this->layers[$underLayerId] = clone $layerTmp; + $this->changePosition($underLayerId, $minLayerPositionX, $minLayerPositionX); + + } else { + + $layerTmp = ImageWorkshop::initFromResourceVar($this->image); + $layerTmp->addLayer(1, $layer, $layerPositionX, $layerPositionY); + + $this->image = $layerTmp->getResult(); // Update background image + } + + unset($layerTmp); + $this->remove($layerId); // Remove the merged layer from the stack + + return true; + } + + return false; + } + + /** + * Merge sublayers in the stack on the layer background + */ + public function mergeAll() + { + $this->image = $this->getResult(); + $this->clearStack(); + } + + /** + * Paste an image on the layer + * You can specify the position left (in pixels) and the position top (in pixels) of the added image relatives to the layer + * Otherwise, it will be set at 0 and 0 + * + * @param string $unit Use one of `UNIT_*` constants, "UNIT_PIXEL" by default + * @param resource $image + * @param integer $positionX + * @param integer $positionY + */ + public function pasteImage($unit = self::UNIT_PIXEL, $image, $positionX = 0, $positionY = 0) + { + if ($unit == self::UNIT_PERCENT) { + + $positionX = round(($positionX / 100) * $this->width); + $positionY = round(($positionY / 100) * $this->height); + } + + imagecopy($this->image, $image, $positionX, $positionY, 0, 0, $image->getWidth(), $image->getHeight()); + } + + // Change sublayer positions + // ========================================================= + + /** + * Change the position of a sublayer for new positions + * + * @param integer $layerId + * @param integer $newPosX + * @param integer $newPosY + * + * @return boolean + */ + public function changePosition($layerId, $newPosX = null, $newPosY = null) + { + // if the sublayer exists in the stack + if ($this->isLayerInIndex($layerId)) { + + if ($newPosX !== null) { + $this->layerPositions[$layerId]['x'] = $newPosX; + } + + if ($newPosY !== null) { + $this->layerPositions[$layerId]['y'] = $newPosY; + } + + return true; + } + + return false; + } + + /** + * Apply a translation on a sublayer that change its positions + * + * @param integer $layerId + * @param integer $addedPosX + * @param integer $addedPosY + * + * @return mixed (array of new positions or false if fail) + */ + public function applyTranslation($layerId, $addedPosX = null, $addedPosY = null) + { + // if the sublayer exists in the stack + if ($this->isLayerInIndex($layerId)) { + + if ($addedPosX !== null) { + $this->layerPositions[$layerId]['x'] += $addedPosX; + } + + if ($addedPosY !== null) { + $this->layerPositions[$layerId]['y'] += $addedPosY; + } + + return $this->layerPositions[$layerId]; + } + + return false; + } + + // Removing sublayers + // ========================================================= + + /** + * Delete a layer (return true if success, false if no sublayer is found) + * + * @param integer $layerId + * + * @return boolean + */ + public function remove($layerId) + { + // if the layer exists in document + if ($this->isLayerInIndex($layerId)) { + + $layerToDeleteLevel = $this->getLayerLevel($layerId); + + // delete + $this->layers[$layerId]->delete(); + unset($this->layers[$layerId]); + unset($this->layerLevels[$layerToDeleteLevel]); + unset($this->layerPositions[$layerId]); + + // One or plural layers are sub of the deleted layer + if (array_key_exists(($layerToDeleteLevel + 1), $this->layerLevels)) { + + ksort($this->layerLevels); + + $layerLevelsTmp = $this->layerLevels; + + $maxOldestLevel = 1; + foreach ($layerLevelsTmp as $levelTmp => $layerIdTmp) { + + if ($levelTmp > $layerToDeleteLevel) { + $this->layerLevels[($levelTmp - 1)] = $layerIdTmp; + } + + $maxOldestLevel++; + } + unset($layerLevelsTmp); + unset($this->layerLevels[$maxOldestLevel]); + } + + $this->highestLayerLevel--; + + return true; + } + + return false; + } + + /** + * Reset the layer stack + * + * @boolean $deleteSubImgVar Delete sublayers image resource var + */ + public function clearStack($deleteSubImgVar = true) + { + if ($deleteSubImgVar) { + foreach ($this->layers as $layer) { + $layer->delete(); + } + } + + unset($this->layers); + unset($this->layerLevels); + unset($this->layerPositions); + + $this->lastLayerId = 0; + $this->layers = array(); + $this->layerLevels = array(); + $this->layerPositions = array(); + $this->highestLayerLevel = 0; + } + + // Perform an action + // ========================================================= + + /** + * Resize the layer by specifying pixel + * + * @param integer $newWidth + * @param integer $newHeight + * @param boolean $converseProportion + * @param integer $positionX + * @param integer $positionY + * @param string $position + * + * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html + * + * $positionX, $positionY, $position can be ignored unless you choose a new width AND a new height AND to conserve proportion. + */ + public function resizeInPixel($newWidth = null, $newHeight = null, $converseProportion = false, $positionX = 0, $positionY = 0, $position = 'MM') + { + $this->resize(self::UNIT_PIXEL, $newWidth, $newHeight, $converseProportion, $positionX, $positionY, $position); + } + + /** + * Resize the layer by specifying a percent + * + * @param float $percentWidth + * @param float $percentHeight + * @param boolean $converseProportion + * @param integer $positionX + * @param integer $positionY + * @param string $position + * + * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html + * + * $positionX, $positionY, $position can be ignored unless you choose a new width AND a new height AND to conserve proportion. + */ + public function resizeInPercent($percentWidth = null, $percentHeight = null, $converseProportion = false, $positionX = 0, $positionY = 0, $position = 'MM') + { + $this->resize(self::UNIT_PERCENT, $percentWidth, $percentHeight, $converseProportion, $positionX, $positionY, $position); + } + + /** + * Resize the layer to fit a bounding box by specifying pixel + * + * @param integer $width + * @param integer $height + * @param boolean $converseProportion + */ + public function resizeToFit($width, $height, $converseProportion = false) + { + if ($this->getWidth() <= $width && $this->getHeight() <= $height) { + return; + } + + if (!$converseProportion) { + $width = min($width, $this->getWidth()); + $height = min($height, $this->getHeight()); + } + + $this->resize(self::UNIT_PIXEL, $width, $height, $converseProportion ? 2 : false); + } + + /** + * Resize the layer + * + * @param string $unit Use one of `UNIT_*` constants, "UNIT_PIXEL" by default + * @param mixed $newWidth (integer or float) + * @param mixed $newHeight (integer or float) + * @param boolean $converseProportion + * @param mixed $positionX (integer or float) + * @param mixed $positionY (integer or float) + * @param string $position + * + * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html + * + * $positionX, $positionY, $position can be ignored unless you choose a new width AND a new height AND to conserve proportion. + */ + public function resize($unit = self::UNIT_PIXEL, $newWidth = null, $newHeight = null, $converseProportion = false, $positionX = 0, $positionY = 0, $position = 'MM') + { + if (is_numeric($newWidth) || is_numeric($newHeight)) { + + if ($unit == self::UNIT_PERCENT) { + + if ($newWidth) { + $newWidth = round(($newWidth / 100) * $this->width); + } + + if ($newHeight) { + $newHeight = round(($newHeight / 100) * $this->height); + } + } + + if (is_numeric($newWidth) && $newWidth <= 0) { + $newWidth = 1; + } + + if (is_numeric($newHeight) && $newHeight <= 0) { + $newHeight = 1; + } + + if ($converseProportion) { // Proportion are conserved + + if ($newWidth && $newHeight) { // Proportions + $newWidth + $newHeight + + if ($this->getWidth() > $this->getHeight()) { + + $this->resizeInPixel($newWidth, null, true); + + if ($this->getHeight() > $newHeight) { + $this->resizeInPixel(null, $newHeight, true); + } + + } else { + + $this->resizeInPixel(null, $newHeight, true); + + if ($this->getWidth() > $newWidth) { + $this->resizeInPixel($newWidth, null, true); + } + } + + if ($converseProportion !== 2 && ($this->getWidth() != $newWidth || $this->getHeight() != $newHeight)) { + + $layerTmp = ImageWorkshop::initVirginLayer($newWidth, $newHeight); + + $layerTmp->addLayer(1, $this, $positionX, $positionY, $position); + + // Reset part of stack + + unset($this->image); + unset($this->layerLevels); + unset($this->layerPositions); + unset($this->layers); + + // Update current object + + $this->width = $layerTmp->getWidth(); + $this->height = $layerTmp->getHeight(); + $this->layerLevels = $layerTmp->layers[1]->getLayerLevels(); + $this->layerPositions = $layerTmp->layers[1]->getLayerPositions(); + $this->layers = $layerTmp->layers[1]->getLayers(); + $this->lastLayerId = $layerTmp->layers[1]->getLastLayerId(); + $this->highestLayerLevel = $layerTmp->layers[1]->getHighestLayerLevel(); + + $translations = $layerTmp->getLayerPositions(1); + + foreach ($this->layers as $id => $layer) { + $this->applyTranslation($id, $translations['x'], $translations['y']); + } + + $layerTmp->layers[1]->clearStack(false); + $this->image = $layerTmp->getResult(); + unset($layerTmp); + } + + return; + + } elseif ($newWidth) { + + $widthResizePercent = $newWidth / ($this->width / 100); + $newHeight = round(($widthResizePercent / 100) * $this->height); + $heightResizePercent = $widthResizePercent; + + } elseif ($newHeight) { + + $heightResizePercent = $newHeight / ($this->height / 100); + $newWidth = round(($heightResizePercent / 100) * $this->width); + $widthResizePercent = $heightResizePercent; + } + + } elseif (($newWidth && !$newHeight) || (!$newWidth && $newHeight)) { // New width OR new height is given + + if ($newWidth) { + + $widthResizePercent = $newWidth / ($this->width / 100); + $heightResizePercent = 100; + $newHeight = $this->height; + + } else { + + $heightResizePercent = $newHeight / ($this->height / 100); + $widthResizePercent = 100; + $newWidth = $this->width; + } + + } else { // New width AND new height are given + + $widthResizePercent = $newWidth / ($this->width / 100); + $heightResizePercent = $newHeight / ($this->height / 100); + } + + // Update the layer positions in the stack + + foreach ($this->layerPositions as $layerId => $layerPosition) { + + $newPosX = round(($widthResizePercent / 100) * $layerPosition['x']); + $newPosY = round(($heightResizePercent / 100) * $layerPosition['y']); + + $this->changePosition($layerId, $newPosX, $newPosY); + } + + // Resize layers in the stack + + $layers = $this->layers; + + foreach ($layers as $key => $layer) { + $layer->resizeInPercent($widthResizePercent, $heightResizePercent); + $this->layers[$key] = $layer; + } + + $this->resizeBackground($newWidth, $newHeight); // Resize the layer + } + } + + /** + * Resize the layer by its largest side by specifying pixel + * + * @param integer $newLargestSideWidth + * @param boolean $converseProportion + */ + public function resizeByLargestSideInPixel($newLargestSideWidth, $converseProportion = false) + { + $this->resizeByLargestSide(self::UNIT_PIXEL, $newLargestSideWidth, $converseProportion); + } + + /** + * Resize the layer by its largest side by specifying percent + * + * @param integer $newLargestSideWidth percent + * @param boolean $converseProportion + */ + public function resizeByLargestSideInPercent($newLargestSideWidth, $converseProportion = false) + { + $this->resizeByLargestSide(self::UNIT_PERCENT, $newLargestSideWidth, $converseProportion); + } + + /** + * Resize the layer by its largest side + * + * @param string $unit + * @param integer $newLargestSideWidth percent + * @param boolean $converseProportion + */ + public function resizeByLargestSide($unit = self::UNIT_PIXEL, $newLargestSideWidth, $converseProportion = false) + { + if ($unit == self::UNIT_PERCENT) { + $newLargestSideWidth = round(($newLargestSideWidth / 100) * $this->getLargestSideWidth()); + } + + if ($this->getWidth() > $this->getHeight()) { + $this->resizeInPixel($newLargestSideWidth, null, $converseProportion); + } else { + $this->resizeInPixel(null, $newLargestSideWidth, $converseProportion); + } + } + + /** + * Resize the layer by its narrow side by specifying pixel + * + * @param integer $newNarrowSideWidth + * @param boolean $converseProportion + */ + public function resizeByNarrowSideInPixel($newNarrowSideWidth, $converseProportion = false) + { + $this->resizeByNarrowSide(self::UNIT_PIXEL, $newNarrowSideWidth, $converseProportion); + } + + /** + * Resize the layer by its narrow side by specifying percent + * + * @param integer $newNarrowSideWidth percent + * @param boolean $converseProportion + */ + public function resizeByNarrowSideInPercent($newNarrowSideWidth, $converseProportion = false) + { + $this->resizeByNarrowSide(self::UNIT_PERCENT, $newNarrowSideWidth, $converseProportion); + } + + /** + * Resize the layer by its narrow side + * + * @param string $unit + * @param integer $newNarrowSideWidth + * @param boolean $converseProportion + */ + public function resizeByNarrowSide($unit = self::UNIT_PIXEL, $newNarrowSideWidth, $converseProportion = false) + { + if ($unit == self::UNIT_PERCENT) { + $newNarrowSideWidth = round(($newNarrowSideWidth / 100) * $this->getNarrowSideWidth()); + } + + if ($this->getWidth() < $this->getHeight()) { + $this->resizeInPixel($newNarrowSideWidth, null, $converseProportion); + } else { + $this->resizeInPixel(null, $newNarrowSideWidth, $converseProportion); + } + } + + /** + * Crop the document by specifying pixels + * + * $backgroundColor: can be set transparent (The script will be longer to execute) + * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html + * + * @param integer $width + * @param integer $height + * @param integer $positionX + * @param integer $positionY + * @param string $position + */ + public function cropInPixel($width = 0, $height = 0, $positionX = 0, $positionY = 0, $position = 'LT') + { + $this->crop(self::UNIT_PIXEL, $width, $height, $positionX, $positionY, $position); + } + + /** + * Crop the document by specifying percent + * + * $backgroundColor can be set transparent (but script could be long to execute) + * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html + * + * @param float $percentWidth + * @param float $percentHeight + * @param float $positionXPercent + * @param float $positionYPercent + * @param string $position + */ + public function cropInPercent($percentWidth = 0, $percentHeight = 0, $positionXPercent = 0, $positionYPercent = 0, $position = 'LT') + { + $this->crop(self::UNIT_PERCENT, $percentWidth, $percentHeight, $positionXPercent, $positionYPercent, $position); + } + + /** + * Crop the document + * + * $backgroundColor can be set transparent (but script could be long to execute) + * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html + * + * @param string $unit + * @param mixed $width (integer or float) + * @param mixed $height (integer or float) + * @param mixed $positionX (integer or float) + * @param mixed $positionY (integer or float) + * @param string $position + */ + public function crop($unit = self::UNIT_PIXEL, $width = 0, $height = 0, $positionX = 0, $positionY = 0, $position = 'LT') + { + if ($width < 0 || $height < 0) { + throw new ImageWorkshopLayerException('You can\'t use negative $width or $height for "'.__METHOD__.'" method.', static::ERROR_NEGATIVE_NUMBER_USED); + } + + if ($unit == self::UNIT_PERCENT) { + + $width = round(($width / 100) * $this->width); + $height = round(($height / 100) * $this->height); + + $positionX = round(($positionX / 100) * $this->width); + $positionY = round(($positionY / 100) * $this->height); + } + + if (($width != $this->width || $positionX == 0) || ($height != $this->height || $positionY == 0)) { + + if ($width == 0) { + $width = 1; + } + + if ($height == 0) { + $height = 1; + } + + $layerTmp = ImageWorkshop::initVirginLayer($width, $height); + $layerClone = ImageWorkshop::initVirginLayer($this->width, $this->height); + + imagedestroy($layerClone->image); + $layerClone->image = $this->image; + + $layerTmp->addLayer(1, $layerClone, -$positionX, -$positionY, $position); + + $newPos = $layerTmp->getLayerPositions(); + $layerNewPosX = $newPos[1]['x']; + $layerNewPosY = $newPos[1]['y']; + + // update the layer + $this->width = $layerTmp->getWidth(); + $this->height = $layerTmp->getHeight(); + $this->image = $layerTmp->getResult(); + unset($layerTmp); + unset($layerClone); + + $this->updateLayerPositionsAfterCropping($layerNewPosX, $layerNewPosY); + } + } + + /** + * Crop the document to a specific aspect ratio by specifying a shift in pixel + * + * $backgroundColor: can be set transparent (The script will be longer to execute) + * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html + * + * @param integer $width + * @param integer $height + * @param integer $positionX + * @param integer $positionY + * @param string $position + */ + public function cropToAspectRatioInPixel($width = 0, $height = 0, $positionX = 0, $positionY = 0, $position = 'LT') + { + $this->cropToAspectRatio(self::UNIT_PIXEL, $width, $height, $positionX, $positionY, $position); + } + + /** + * Crop the document to a specific aspect ratio by specifying a shift in percent + * + * $backgroundColor can be set transparent (but script could be long to execute) + * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html + * + * @param integer $width + * @param integer $height + * @param float $positionXPercent + * @param float $positionYPercent + * @param string $position + */ + public function cropToAspectRatioInPercent($width = 0, $height = 0, $positionXPercent = 0, $positionYPercent = 0, $position = 'LT') + { + $this->cropToAspectRatio(self::UNIT_PERCENT, $width, $height, $positionXPercent, $positionYPercent, $position); + } + + /** + * Crop the document to a specific aspect ratio + * + * $backgroundColor can be set transparent (but script could be long to execute) + * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html + * + * @param string $unit + * @param integer $width (integer or float) + * @param integer $height (integer or float) + * @param mixed $positionX (integer or float) + * @param mixed $positionY (integer or float) + * @param string $position + */ + public function cropToAspectRatio($unit = self::UNIT_PIXEL, $width = 0, $height = 0, $positionX = 0, $positionY = 0, $position = 'LT') + { + if ($width < 0 || $height < 0) { + throw new ImageWorkshopLayerException('You can\'t use negative $width or $height for "'.__METHOD__.'" method.', static::ERROR_NEGATIVE_NUMBER_USED); + } + + if ($width == 0) { + $width = 1; + } + + if ($height == 0) { + $height = 1; + } + + if ($this->width / $this->height <= $width / $height) { + $newWidth = $this->width; + $newHeight = round($height * ($this->width / $width)); + } else { + $newWidth = round($width * ($this->height / $height)); + $newHeight = $this->height; + } + + if ($unit == self::UNIT_PERCENT) { + $positionX = round(($positionX / 100) * ($this->width - $newWidth)); + $positionY = round(($positionY / 100) * ($this->height - $newHeight)); + } + + $this->cropInPixel($newWidth, $newHeight, $positionX, $positionY, $position); + } + + /** + * Crop the maximum possible from left top ("LT"), "RT"... by specifying a shift in pixel + * + * $backgroundColor can be set transparent (but script could be long to execute) + * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html + * + * @param integer $width + * @param integer $height + * @param integer $positionX + * @param integer $positionY + * @param string $position + */ + public function cropMaximumInPixel($positionX = 0, $positionY = 0, $position = 'LT') + { + $this->cropMaximum(self::UNIT_PIXEL, $positionX, $positionY, $position); + } + + /** + * Crop the maximum possible from left top ("LT"), "RT"... by specifying a shift in percent + * + * $backgroundColor can be set transparent (but script could be long to execute) + * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html + * + * @param integer $width + * @param integer $height + * @param integer $positionXPercent + * @param integer $positionYPercent + * @param string $position + */ + public function cropMaximumInPercent($positionXPercent = 0, $positionYPercent = 0, $position = 'LT') + { + $this->cropMaximum(self::UNIT_PERCENT, $positionXPercent, $positionYPercent, $position); + } + + /** + * Crop the maximum possible from left top + * + * $backgroundColor can be set transparent (but script could be long to execute) + * $position: http://phpimageworkshop.com/doc/22/corners-positions-schema-of-an-image.html + * + * @param string $unit + * @param integer $width + * @param integer $height + * @param integer $positionX + * @param integer $positionY + * @param string $position + */ + public function cropMaximum($unit = self::UNIT_PIXEL, $positionX = 0, $positionY = 0, $position = 'LT') + { + $narrowSide = $this->getNarrowSideWidth(); + + if ($unit == self::UNIT_PERCENT) { + $positionX = round(($positionX / 100) * $this->width); + $positionY = round(($positionY / 100) * $this->height); + } + + $this->cropInPixel($narrowSide, $narrowSide, $positionX, $positionY, $position); + } + + /** + * Rotate the layer (in degree) + * + * @param float $degrees + */ + public function rotate($degrees) + { + if ($degrees != 0) { + + if ($degrees < -360 || $degrees > 360) { + $degrees = $degrees % 360; + } + + if ($degrees < 0 && $degrees >= -360) { + $degrees = 360 + $degrees; + } + + // Rotate the layer background image + $imageRotated = imagerotate($this->image, -$degrees, -1); + imagealphablending($imageRotated, true); + imagesavealpha($imageRotated, true); + + unset($this->image); + + $this->image = $imageRotated; + + $oldWidth = $this->width; + $oldHeight = $this->height; + + $this->width = imagesx($this->image); + $this->height = imagesy($this->image); + + foreach ($this->layers as $layerId => $layer) { + + $layerSelfOldCenterPosition = array( + 'x' => $layer->width / 2, + 'y' => $layer->height / 2, + ); + + $smallImageCenter = array( + 'x' => $layerSelfOldCenterPosition['x'] + $this->layerPositions[$layerId]['x'], + 'y' => $layerSelfOldCenterPosition['y'] + $this->layerPositions[$layerId]['y'], + ); + + $this->layers[$layerId]->rotate($degrees); + + $ro = sqrt(pow($smallImageCenter['x'], 2) + pow($smallImageCenter['y'], 2)); + + $teta = (acos($smallImageCenter['x'] / $ro)) * 180 / pi(); + + $a = $ro * cos(($teta + $degrees) * pi() / 180); + $b = $ro * sin(($teta + $degrees) * pi() / 180); + + if ($degrees > 0 && $degrees <= 90) { + + $newPositionX = $a - ($this->layers[$layerId]->width / 2) + $oldHeight * sin(($degrees * pi()) / 180); + $newPositionY = $b - ($this->layers[$layerId]->height / 2); + + } elseif ($degrees > 90 && $degrees <= 180) { + + $newPositionX = $a - ($this->layers[$layerId]->width / 2) + $this->width; + $newPositionY = $b - ($this->layers[$layerId]->height / 2) + $oldHeight * (-cos(($degrees) * pi() / 180)); + + } elseif ($degrees > 180 && $degrees <= 270) { + + $newPositionX = $a - ($this->layers[$layerId]->width / 2) + $oldWidth * (-cos(($degrees) * pi() / 180)); + $newPositionY = $b - ($this->layers[$layerId]->height / 2) + $this->height; + + } else { + + $newPositionX = $a - ($this->layers[$layerId]->width / 2); + $newPositionY = $b - ($this->layers[$layerId]->height / 2) + $oldWidth * (-sin(($degrees) * pi() / 180)); + } + + $this->layerPositions[$layerId] = array( + 'x' => $newPositionX, + 'y' => $newPositionY, + ); + } + } + } + + /** + * Change the opacity of the layer + * $recursive: apply it on sublayers + * + * @param integer $opacity + * @param boolean $recursive + */ + public function opacity($opacity, $recursive = true) + { + if ($recursive) { + + $layers = $this->layers; + + foreach ($layers as $key => $layer) { + $layer->opacity($opacity, true); + $this->layers[$key] = $layer; + } + } + + $transparentImage = ImageWorkshopLib::generateImage($this->getWidth(), $this->getHeight()); + + ImageWorkshopLib::imageCopyMergeAlpha($transparentImage, $this->image, 0, 0, 0, 0, $this->getWidth(), $this->getHeight(), $opacity); + + unset($this->image); + $this->image = $transparentImage; + unset($transparentImage); + } + + /** + * Apply a filter on the layer + * Be careful: some filters can damage transparent images, use it sparingly ! (A good pratice is to use mergeAll on your layer before applying a filter) + * + * @param int $filterType (http://www.php.net/manual/en/function.imagefilter.php) + * @param int $arg1 + * @param int $arg2 + * @param int $arg3 + * @param int $arg4 + * @param boolean $recursive + */ + public function applyFilter($filterType, $arg1 = null, $arg2 = null, $arg3 = null, $arg4 = null, $recursive = false) + { + if ($filterType == IMG_FILTER_COLORIZE) { + imagefilter($this->image, $filterType, $arg1, $arg2, $arg3, $arg4); + } elseif ($filterType == IMG_FILTER_BRIGHTNESS || $filterType == IMG_FILTER_CONTRAST || $filterType == IMG_FILTER_SMOOTH) { + imagefilter($this->image, $filterType, $arg1); + } elseif ($filterType == IMG_FILTER_PIXELATE) { + imagefilter($this->image, $filterType, $arg1, $arg2); + } else { + imagefilter($this->image, $filterType); + } + + if ($recursive) { + + $layers = $this->layers; + + foreach($layers as $layerId => $layer) { + $this->layers[$layerId]->applyFilter($filterType, $arg1, $arg2, $arg3, $arg4, true); + } + } + } + + /** + * Apply horizontal or vertical flip (Transformation) + * + * @param string $type + */ + public function flip($type = 'horizontal') + { + $layers = $this->layers; + + foreach ($layers as $key => $layer) { + + $layer->flip($type); + $this->layers[$key] = $layer; + } + + $temp = ImageWorkshopLib::generateImage($this->width, $this->height); + + if ($type == 'horizontal') { + + imagecopyresampled($temp, $this->image, 0, 0, $this->width - 1, 0, $this->width, $this->height, -$this->width, $this->height); + $this->image = $temp; + + foreach ($this->layerPositions as $layerId => $layerPositions) { + + $this->changePosition($layerId, $this->width - $this->layers[$layerId]->getWidth() - $layerPositions['x'], $layerPositions['y']); + } + + } elseif ($type == 'vertical') { + + imagecopyresampled($temp, $this->image, 0, 0, 0, $this->height - 1, $this->width, $this->height, $this->width, -$this->height); + $this->image = $temp; + + foreach ($this->layerPositions as $layerId => $layerPositions) { + + $this->changePosition($layerId, $layerPositions['x'], $this->height - $this->layers[$layerId]->getHeight() - $layerPositions['y']); + } + } + + unset($temp); + } + + /** + * Add a text on the background image of the layer using a default font registered in GD + * + * @param string $text + * @param integer $font + * @param string $color + * @param integer $positionX + * @param integer $positionY + * @param string $align + */ + public function writeText($text, $font = 1, $color = 'ffffff', $positionX = 0, $positionY = 0, $align = 'horizontal') + { + $RGBTextColor = ImageWorkshopLib::convertHexToRGB($color); + $textColor = imagecolorallocate($this->image, $RGBTextColor['R'], $RGBTextColor['G'], $RGBTextColor['B']); + + if ($align == 'horizontal') { + imagestring($this->image, $font, $positionX, $positionY, $text, $textColor); + } else { + imagestringup($this->image, $font, $positionX, $positionY, $text, $textColor); + } + } + + /** + * Add a text on the background image of the layer using a font localized at $fontPath + * Return the text coordonates + * + * @param string $text + * @param integer $fontPath + * @param integer $fontSize + * @param string $color + * @param integer $positionX + * @param integer $positionY + * @param integer $fontRotation + * + * @return array + */ + public function write($text, $fontPath, $fontSize = 13, $color = 'ffffff', $positionX = 0, $positionY = 0, $fontRotation = 0) + { + if (!file_exists($fontPath)) { + throw new ImageWorkshopLayerException('Can\'t find a font file at this path : "'.$fontPath.'".', static::ERROR_FONT_NOT_FOUND); + } + + $RGBTextColor = ImageWorkshopLib::convertHexToRGB($color); + $textColor = imagecolorallocate($this->image, $RGBTextColor['R'], $RGBTextColor['G'], $RGBTextColor['B']); + + return imagettftext($this->image, $fontSize, $fontRotation, $positionX, $positionY, $textColor, $fontPath, $text); + } + + // Manage the result + // ========================================================= + + /** + * Return a merged resource image + * + * $backgroundColor is really usefull if you want to save a JPG or GIF, because the transparency of the background + * would be remove for a colored background, so you should choose a color like "ffffff" (white) + * + * @param string $backgroundColor + * + * @return resource + */ + public function getResult($backgroundColor = null) + { + $imagesToMerge = array(); + ksort($this->layerLevels); + + foreach ($this->layerLevels as $layerLevel => $layerId) { + + $imagesToMerge[$layerLevel] = $this->layers[$layerId]->getResult(); + + // Layer positions + if ($this->layerPositions[$layerId]['x'] != 0 || $this->layerPositions[$layerId]['y'] != 0) { + + $virginLayoutImageTmp = ImageWorkshopLib::generateImage($this->width, $this->height); + ImageWorkshopLib::mergeTwoImages($virginLayoutImageTmp, $imagesToMerge[$layerLevel], $this->layerPositions[$layerId]['x'], $this->layerPositions[$layerId]['y'], 0, 0); + $imagesToMerge[$layerLevel] = $virginLayoutImageTmp; + unset($virginLayoutImageTmp); + } + } + + $iterator = 1; + $mergedImage = $this->image; + ksort($imagesToMerge); + + foreach ($imagesToMerge as $imageLevel => $image) { + ImageWorkshopLib::mergeTwoImages($mergedImage, $image); + $iterator++; + } + + $opacity = 127; + + if ($backgroundColor && $backgroundColor != 'transparent') { + $opacity = 0; + } + + $backgroundImage = ImageWorkshopLib::generateImage($this->width, $this->height, $backgroundColor, $opacity); + ImageWorkshopLib::mergeTwoImages($backgroundImage, $mergedImage); + $mergedImage = $backgroundImage; + unset($backgroundImage); + + return $mergedImage; + } + + /** + * Save the resulting image at the specified path + * + * $backgroundColor is really usefull if you want to save a JPG or GIF, because the transparency of the background + * would be remove for a colored background, so you should choose a color like "ffffff" (white) + * + * If the file already exists, it will be override ! + * + * $imageQuality is useless for GIF + * + * Ex: $folder = __DIR__."/../web/images/2012" + * $imageName = "butterfly.jpg" + * $createFolders = true + * $imageQuality = 95 + * $backgroundColor = "ffffff" + * + * @param string $folder + * @param string $imageName + * @param boolean $createFolders + * @param string $backgroundColor + * @param integer $imageQuality + * @param boolean $interlace + */ + public function save($folder, $imageName, $createFolders = true, $backgroundColor = null, $imageQuality = 75, $interlace = false) + { + if (!is_file($folder)) { + + if (is_dir($folder) || $createFolders) { + + // Creating the folders if they don't exist + if (!is_dir($folder) && $createFolders) { + $oldUmask = umask(0); + mkdir($folder, 0777, true); + umask($oldUmask); + chmod($folder, 0777); + } + + $extension = explode('.', $imageName); + $extension = strtolower($extension[count($extension) - 1]); + + $filename = $folder.'/'.$imageName; + + if (($extension == 'jpg' || $extension == 'jpeg' || $extension == 'gif') && (!$backgroundColor || $backgroundColor == 'transparent')) { + $backgroundColor = 'ffffff'; + } + + $image = $this->getResult($backgroundColor); + + imageinterlace($image, (int) $interlace); + + if ($extension == 'jpg' || $extension == 'jpeg') { + + imagejpeg($image, $filename, $imageQuality); + unset($image); + + } elseif ($extension == 'gif') { + + imagegif($image, $filename); + unset($image); + + } elseif ($extension == 'png') { + + $imageQuality = $imageQuality / 10; + $imageQuality -= 1; + + imagepng($image, $filename, $imageQuality); + unset($image); + } + } + } + } + + // Checkers + // ========================================================= + + /** + * Check if a sublayer exists in the stack for a given id + * + * @param integer $layerId + * + * @return boolean + */ + public function isLayerInIndex($layerId) + { + if (array_key_exists($layerId, $this->layers)) { + return true; + } + + return false; + } + + // Getter / Setter + // ========================================================= + + /** + * Return the narrow side width of the layer + * + * @return integer + */ + public function getNarrowSideWidth() + { + $narrowSideWidth = $this->getWidth(); + + if ($this->getHeight() < $narrowSideWidth) { + $narrowSideWidth = $this->getHeight(); + } + + return $narrowSideWidth; + } + + /** + * Return the largest side width of the layer + * + * @return integer + */ + public function getLargestSideWidth() + { + $largestSideWidth = $this->getWidth(); + + if ($this->getHeight() > $largestSideWidth) { + $largestSideWidth = $this->getHeight(); + } + + return $largestSideWidth; + } + + /** + * Get the level of a sublayer + * Return sublayer level if success or false if layer isn't found + * + * @param integer $layerId + * + * @return mixed (integer or boolean) + */ + public function getLayerLevel($layerId) + { + if ($this->isLayerInIndex($layerId)) { // if the layer exists in document + return array_search($layerId, $this->layerLevels); + } + + return false; + } + + /** + * Get a sublayer in the stack + * Don't forget to use clone method: $b = clone $a->getLayer(3); + * + * @param integer $layerId + * + * @return ImageWorkshop + */ + public function getLayer($layerId) + { + return $this->layers[$layerId]; + } + + /** + * Getter width + * + * @return integer + */ + public function getWidth() + { + return $this->width; + } + + /** + * Getter height + * + * @return integer + */ + public function getHeight() + { + return $this->height; + } + + /** + * Getter image + * + * @return resource + */ + public function getImage() + { + return $this->image; + } + + /** + * Getter layers + * + * @return array + */ + public function getLayers() + { + return $this->layers; + } + + /** + * Getter layerLevels + * + * @return array + */ + public function getLayerLevels() + { + return $this->layerLevels; + } + + /** + * Getter layerPositions + * + * Get all the positions of the sublayers, + * or when specifying $layerId, get the position of this sublayer + * + * @param integer $layerId + * + * @return mixed (array or boolean) + */ + public function getLayerPositions($layerId = null) + { + if (!$layerId) { + + return $this->layerPositions; + + } elseif ($this->isLayerInIndex($layerId)) { // if the sublayer exists in the stack + + return $this->layerPositions[$layerId]; + } + + return false; + } + + /** + * Getter highestLayerLevel + * + * @return array + */ + public function getHighestLayerLevel() + { + return $this->highestLayerLevel; + } + + /** + * Getter lastLayerId + * + * @return array + */ + public function getLastLayerId() + { + return $this->lastLayerId; + } + + // Internals + // ========================================================= + + /** + * Delete the current object + */ + public function delete() + { + imagedestroy($this->image); + $this->clearStack(); + } + + /** + * Create a new background image var from the old background image var + */ + public function createNewVarFromBackgroundImage() + { + $virginImage = ImageWorkshopLib::generateImage($this->getWidth(), $this->getHeight()); // New background image + + ImageWorkshopLib::mergeTwoImages($virginImage, $this->image, 0, 0, 0, 0); + unset($this->image); + + $this->image = $virginImage; + unset($virginImage); + + $layers = $this->layers; + + foreach($layers as $layerId => $layer) { + $this->layers[$layerId] = clone $this->layers[$layerId]; + } + } + + /** + * Index a sublayer in the layer stack + * Return an array containing the generated sublayer id and its final level: + * array("layerLevel" => integer, "id" => integer) + * + * @param integer $layerLevel + * @param ImageWorkshopLayer $layer + * @param integer $positionX + * @param integer $positionY + * @param string $position + * + * @return array + */ + protected function indexLayer($layerLevel, $layer, $positionX = 0, $positionY = 0, $position) + { + // Choose an id for the added layer + $layerId = $this->lastLayerId + 1; + + // Clone $layer to duplicate image resource var + $layer = clone $layer; + + // Add the layer in the stack + $this->layers[$layerId] = $layer; + + // Add the layer positions in the main layer + $this->layerPositions[$layerId] = ImageWorkshopLib::calculatePositions($this->getWidth(), $this->getHeight(), $layer->getWidth(), $layer->getHeight(), $positionX, $positionY, $position); + + // Update the lastLayerId of the workshop + $this->lastLayerId = $layerId; + + // Add the layer level in the stack + $layerLevel = $this->indexLevelInDocument($layerLevel, $layerId); + + return array( + 'layerLevel' => $layerLevel, + 'id' => $layerId, + ); + } + + /** + * Index a layer level and update the layers levels in the document + * Return the corrected level of the layer + * + * @param integer $layerLevel + * @param integer $layerId + * + * @return integer + */ + protected function indexLevelInDocument($layerLevel, $layerId) + { + if (array_key_exists($layerLevel, $this->layerLevels)) { // Level already exists + + ksort($this->layerLevels); // All layers after this level and the layer which have this level are updated + $layerLevelsTmp = $this->layerLevels; + + foreach ($layerLevelsTmp as $levelTmp => $layerIdTmp) { + if ($levelTmp >= $layerLevel) { + $this->layerLevels[$levelTmp + 1] = $layerIdTmp; + } + } + + unset($layerLevelsTmp); + + } else { // Level isn't taken + if ($this->highestLayerLevel < $layerLevel) { // If given level is too high, proceed adjustement + $layerLevel = $this->highestLayerLevel + 1; + } + } + + $this->layerLevels[$layerLevel] = $layerId; + $this->highestLayerLevel = max(array_flip($this->layerLevels)); // Update $highestLayerLevel + + return $layerLevel; + } + + /** + * Update the positions of layers in the stack after cropping + * + * @param integer $positionX + * @param integer $positionY + */ + public function updateLayerPositionsAfterCropping($positionX, $positionY) + { + foreach ($this->layers as $layerId => $layer) { + + $oldLayerPosX = $this->layerPositions[$layerId]['x']; + $oldLayerPosY = $this->layerPositions[$layerId]['y']; + + $newLayerPosX = $oldLayerPosX + $positionX; + $newLayerPosY = $oldLayerPosY + $positionY; + + $this->changePosition($layerId, $newLayerPosX, $newLayerPosY); + } + } + + /** + * Resize the background of a layer + * + * @param integer $newWidth + * @param integer $newHeight + */ + public function resizeBackground($newWidth, $newHeight) + { + $oldWidth = $this->width; + $oldHeight = $this->height; + + $this->width = $newWidth; + $this->height = $newHeight; + + $virginLayoutImage = ImageWorkshopLib::generateImage($this->width, $this->height); + + imagecopyresampled($virginLayoutImage, $this->image, 0, 0, 0, 0, $this->width, $this->height, $oldWidth, $oldHeight); + + unset($this->image); + $this->image = $virginLayoutImage; + } + + // Deprecated, don't use anymore + // ========================================================= + + /** + * @deprecated + */ + public function resizeInPourcent($percentWidth = null, $percentHeight = null, $converseProportion = false, $positionX = 0, $positionY = 0, $position = 'MM') + { + throw new ImageWorkshopLayerException('Method resizeInPourcent() was renamed resizeInPercent(). Use resizeInPercent() instead.', static::METHOD_DEPRECATED); + } + + /** + * @deprecated + */ + public function resizeByLargestSideInPourcent($newLargestSideWidth, $converseProportion = false) + { + throw new ImageWorkshopLayerException('Method resizeByLargestSideInPourcent() was renamed resizeByLargestSideInPercent(). Use resizeByLargestSideInPercent() instead.', static::METHOD_DEPRECATED); + } + + /** + * @deprecated + */ + public function resizeByNarrowSideInPourcent($newNarrowSideWidth, $converseProportion = false) + { + throw new ImageWorkshopLayerException('Method resizeByNarrowSideInPourcent() was renamed resizeByNarrowSideInPercent(). Use resizeByNarrowSideInPercent() instead.', static::METHOD_DEPRECATED); + } + + /** + * @deprecated + */ + public function cropInPourcent($percentWidth = 0, $percentHeight = 0, $positionXPercent = 0, $positionYPercent = 0, $position = 'LT') + { + throw new ImageWorkshopLayerException('Method cropInPourcent() was renamed cropInPercent(). Use cropInPercent() instead.', static::METHOD_DEPRECATED); + } + + /** + * @deprecated + */ + public function cropMaximumInPourcent($positionXPercent = 0, $positionYPercent = 0, $position = 'LT') + { + throw new ImageWorkshopLayerException('Method cropMaximumInPourcent() was renamed cropMaximumInPercent(). Use cropMaximumInPercent() instead.', static::METHOD_DEPRECATED); + } +} diff --git a/PHPImageWorkshop/Core/ImageWorkshopLib.php b/PHPImageWorkshop/Core/ImageWorkshopLib.php index ed928ee..c650218 100644 --- a/PHPImageWorkshop/Core/ImageWorkshopLib.php +++ b/PHPImageWorkshop/Core/ImageWorkshopLib.php @@ -1,299 +1,299 @@ - $layerPositionX, - 'y' => $layerPositionY, - ); - } - - /** - * Convert Hex color to RGB color format - * - * @param string $hex - * - * @return array - */ - public static function convertHexToRGB($hex) - { - return array( - 'R' => (int) base_convert(substr($hex, 0, 2), 16, 10), - 'G' => (int) base_convert(substr($hex, 2, 2), 16, 10), - 'B' => (int) base_convert(substr($hex, 4, 2), 16, 10), - ); - } - - /** - * Generate a new image resource var - * - * @param integer $width - * @param integer $height - * @param string $color - * @param integer $opacity - * - * @return resource - */ - public static function generateImage($width = 100, $height = 100, $color = 'ffffff', $opacity = 127) - { - $RGBColors = ImageWorkshopLib::convertHexToRGB($color); - - $image = imagecreatetruecolor($width, $height); - imagesavealpha($image, true); - $color = imagecolorallocatealpha($image, $RGBColors['R'], $RGBColors['G'], $RGBColors['B'], $opacity); - imagefill($image, 0, 0, $color); - - return $image; - } - - /** - * Return dimension of a text - * - * @param $fontSize - * @param $fontAngle - * @param $fontFile - * @param $text - * - * @return array or boolean - */ - public static function getTextBoxDimension($fontSize, $fontAngle, $fontFile, $text) - { - if (!file_exists($fontFile)) { - throw new ImageWorkshopLibException('Can\'t find a font file at this path : "'.$fontFile.'".', static::ERROR_FONT_NOT_FOUND); - } - - $box = imagettfbbox($fontSize, $fontAngle, $fontFile, $text); - - if (!$box) { - - return false; - } - - $minX = min(array($box[0], $box[2], $box[4], $box[6])); - $maxX = max(array($box[0], $box[2], $box[4], $box[6])); - $minY = min(array($box[1], $box[3], $box[5], $box[7])); - $maxY = max(array($box[1], $box[3], $box[5], $box[7])); - $width = ($maxX - $minX); - $height = ($maxY - $minY); - $left = abs($minX) + $width; - $top = abs($minY) + $height; - - // to calculate the exact bounding box, we write the text in a large image - $img = @imagecreatetruecolor($width << 2, $height << 2); - $white = imagecolorallocate($img, 255, 255, 255); - $black = imagecolorallocate($img, 0, 0, 0); - imagefilledrectangle($img, 0, 0, imagesx($img), imagesy($img), $black); - - // for ensure that the text is completely in the image - imagettftext($img, $fontSize, $fontAngle, $left, $top, $white, $fontFile, $text); - - // start scanning (0=> black => empty) - $rleft = $w4 = $width<<2; - $rright = 0; - $rbottom = 0; - $rtop = $h4 = $height<<2; - - for ($x = 0; $x < $w4; $x++) { - - for ($y = 0; $y < $h4; $y++) { - - if (imagecolorat($img, $x, $y)) { - - $rleft = min($rleft, $x); - $rright = max($rright, $x); - $rtop = min($rtop, $y); - $rbottom = max($rbottom, $y); - } - } - } - - imagedestroy($img); - - return array( - 'left' => $left - $rleft, - 'top' => $top - $rtop, - 'width' => $rright - $rleft + 1, - 'height' => $rbottom - $rtop + 1, - ); - } - - /** - * Copy an image on another one and converse transparency - * - * @param resource $destImg - * @param resource $srcImg - * @param integer $destX - * @param integer $destY - * @param integer $srcX - * @param integer $srcY - * @param integer $srcW - * @param integer $srcH - * @param integer $pct - */ - public static function imageCopyMergeAlpha(&$destImg, &$srcImg, $destX, $destY, $srcX, $srcY, $srcW, $srcH, $pct = 0) - { - $destX = (int) $destX; - $destY = (int) $destY; - $srcX = (int) $srcX; - $srcY = (int) $srcY; - $srcW = (int) $srcW; - $srcH = (int) $srcH; - $pct = (int) $pct; - $destW = imageSX($destImg); - $destH = imageSY($destImg); - - for ($y = 0; $y < $srcH + $srcY; $y++) { - - for ($x = 0; $x < $srcW + $srcX; $x++) { - - if ($x + $destX >= 0 && $x + $destX < $destW && $x + $srcX >= 0 && $x + $srcX < $srcW && $y + $destY >= 0 && $y + $destY < $destH && $y + $srcY >= 0 && $y + $srcY < $srcH) { - - $destPixel = imageColorsForIndex($destImg, imageColorat($destImg, $x + $destX, $y + $destY)); - $srcImgColorat = imageColorat($srcImg, $x + $srcX, $y + $srcY); - - if ($srcImgColorat >= 0) { - - $srcPixel = imageColorsForIndex($srcImg, $srcImgColorat); - - $srcAlpha = 1 - ($srcPixel['alpha'] / 127); - $destAlpha = 1 - ($destPixel['alpha'] / 127); - $opacity = $srcAlpha * $pct / 100; - - if ($destAlpha >= $opacity) { - $alpha = $destAlpha; - } - - if ($destAlpha < $opacity) { - $alpha = $opacity; - } - - if ($alpha > 1) { - $alpha = 1; - } - - if ($opacity > 0) { - - $destRed = round((($destPixel['red'] * $destAlpha * (1 - $opacity)))); - $destGreen = round((($destPixel['green'] * $destAlpha * (1 - $opacity)))); - $destBlue = round((($destPixel['blue'] * $destAlpha * (1 - $opacity)))); - $srcRed = round((($srcPixel['red'] * $opacity))); - $srcGreen = round((($srcPixel['green'] * $opacity))); - $srcBlue = round((($srcPixel['blue'] * $opacity))); - $red = round(($destRed + $srcRed ) / ($destAlpha * (1 - $opacity) + $opacity)); - $green = round(($destGreen + $srcGreen) / ($destAlpha * (1 - $opacity) + $opacity)); - $blue = round(($destBlue + $srcBlue ) / ($destAlpha * (1 - $opacity) + $opacity)); - - if ($red > 255) { - $red = 255; - } - - if ($green > 255) { - $green = 255; - } - - if ($blue > 255) { - $blue = 255; - } - - $alpha = round((1 - $alpha) * 127); - $color = imageColorAllocateAlpha($destImg, $red, $green, $blue, $alpha); - imageSetPixel($destImg, $x + $destX, $y + $destY, $color); - } - } - } - } - } - } - - /** - * Merge two image var - * - * @param resource $destinationImage - * @param resource $sourceImage - * @param integer $destinationPosX - * @param integer $destinationPosY - * @param integer $sourcePosX - * @param integer $sourcePosY - */ - public static function mergeTwoImages(&$destinationImage, $sourceImage, $destinationPosX = 0, $destinationPosY = 0, $sourcePosX = 0, $sourcePosY = 0) - { - imageCopy($destinationImage, $sourceImage, $destinationPosX, $destinationPosY, $sourcePosX, $sourcePosY, imageSX($sourceImage), imageSY($sourceImage)); - } + $layerPositionX, + 'y' => $layerPositionY, + ); + } + + /** + * Convert Hex color to RGB color format + * + * @param string $hex + * + * @return array + */ + public static function convertHexToRGB($hex) + { + return array( + 'R' => (int) base_convert(substr($hex, 0, 2), 16, 10), + 'G' => (int) base_convert(substr($hex, 2, 2), 16, 10), + 'B' => (int) base_convert(substr($hex, 4, 2), 16, 10), + ); + } + + /** + * Generate a new image resource var + * + * @param integer $width + * @param integer $height + * @param string $color + * @param integer $opacity + * + * @return resource + */ + public static function generateImage($width = 100, $height = 100, $color = 'ffffff', $opacity = 127) + { + $RGBColors = ImageWorkshopLib::convertHexToRGB($color); + + $image = imagecreatetruecolor($width, $height); + imagesavealpha($image, true); + $color = imagecolorallocatealpha($image, $RGBColors['R'], $RGBColors['G'], $RGBColors['B'], $opacity); + imagefill($image, 0, 0, $color); + + return $image; + } + + /** + * Return dimension of a text + * + * @param $fontSize + * @param $fontAngle + * @param $fontFile + * @param $text + * + * @return array or boolean + */ + public static function getTextBoxDimension($fontSize, $fontAngle, $fontFile, $text) + { + if (!file_exists($fontFile)) { + throw new ImageWorkshopLibException('Can\'t find a font file at this path : "'.$fontFile.'".', static::ERROR_FONT_NOT_FOUND); + } + + $box = imagettfbbox($fontSize, $fontAngle, $fontFile, $text); + + if (!$box) { + + return false; + } + + $minX = min(array($box[0], $box[2], $box[4], $box[6])); + $maxX = max(array($box[0], $box[2], $box[4], $box[6])); + $minY = min(array($box[1], $box[3], $box[5], $box[7])); + $maxY = max(array($box[1], $box[3], $box[5], $box[7])); + $width = ($maxX - $minX); + $height = ($maxY - $minY); + $left = abs($minX) + $width; + $top = abs($minY) + $height; + + // to calculate the exact bounding box, we write the text in a large image + $img = @imagecreatetruecolor($width << 2, $height << 2); + $white = imagecolorallocate($img, 255, 255, 255); + $black = imagecolorallocate($img, 0, 0, 0); + imagefilledrectangle($img, 0, 0, imagesx($img), imagesy($img), $black); + + // for ensure that the text is completely in the image + imagettftext($img, $fontSize, $fontAngle, $left, $top, $white, $fontFile, $text); + + // start scanning (0=> black => empty) + $rleft = $w4 = $width<<2; + $rright = 0; + $rbottom = 0; + $rtop = $h4 = $height<<2; + + for ($x = 0; $x < $w4; $x++) { + + for ($y = 0; $y < $h4; $y++) { + + if (imagecolorat($img, $x, $y)) { + + $rleft = min($rleft, $x); + $rright = max($rright, $x); + $rtop = min($rtop, $y); + $rbottom = max($rbottom, $y); + } + } + } + + imagedestroy($img); + + return array( + 'left' => $left - $rleft, + 'top' => $top - $rtop, + 'width' => $rright - $rleft + 1, + 'height' => $rbottom - $rtop + 1, + ); + } + + /** + * Copy an image on another one and converse transparency + * + * @param resource $destImg + * @param resource $srcImg + * @param integer $destX + * @param integer $destY + * @param integer $srcX + * @param integer $srcY + * @param integer $srcW + * @param integer $srcH + * @param integer $pct + */ + public static function imageCopyMergeAlpha(&$destImg, &$srcImg, $destX, $destY, $srcX, $srcY, $srcW, $srcH, $pct = 0) + { + $destX = (int) $destX; + $destY = (int) $destY; + $srcX = (int) $srcX; + $srcY = (int) $srcY; + $srcW = (int) $srcW; + $srcH = (int) $srcH; + $pct = (int) $pct; + $destW = imageSX($destImg); + $destH = imageSY($destImg); + + for ($y = 0; $y < $srcH + $srcY; $y++) { + + for ($x = 0; $x < $srcW + $srcX; $x++) { + + if ($x + $destX >= 0 && $x + $destX < $destW && $x + $srcX >= 0 && $x + $srcX < $srcW && $y + $destY >= 0 && $y + $destY < $destH && $y + $srcY >= 0 && $y + $srcY < $srcH) { + + $destPixel = imageColorsForIndex($destImg, imageColorat($destImg, $x + $destX, $y + $destY)); + $srcImgColorat = imageColorat($srcImg, $x + $srcX, $y + $srcY); + + if ($srcImgColorat >= 0) { + + $srcPixel = imageColorsForIndex($srcImg, $srcImgColorat); + + $srcAlpha = 1 - ($srcPixel['alpha'] / 127); + $destAlpha = 1 - ($destPixel['alpha'] / 127); + $opacity = $srcAlpha * $pct / 100; + + if ($destAlpha >= $opacity) { + $alpha = $destAlpha; + } + + if ($destAlpha < $opacity) { + $alpha = $opacity; + } + + if ($alpha > 1) { + $alpha = 1; + } + + if ($opacity > 0) { + + $destRed = round((($destPixel['red'] * $destAlpha * (1 - $opacity)))); + $destGreen = round((($destPixel['green'] * $destAlpha * (1 - $opacity)))); + $destBlue = round((($destPixel['blue'] * $destAlpha * (1 - $opacity)))); + $srcRed = round((($srcPixel['red'] * $opacity))); + $srcGreen = round((($srcPixel['green'] * $opacity))); + $srcBlue = round((($srcPixel['blue'] * $opacity))); + $red = round(($destRed + $srcRed ) / ($destAlpha * (1 - $opacity) + $opacity)); + $green = round(($destGreen + $srcGreen) / ($destAlpha * (1 - $opacity) + $opacity)); + $blue = round(($destBlue + $srcBlue ) / ($destAlpha * (1 - $opacity) + $opacity)); + + if ($red > 255) { + $red = 255; + } + + if ($green > 255) { + $green = 255; + } + + if ($blue > 255) { + $blue = 255; + } + + $alpha = round((1 - $alpha) * 127); + $color = imageColorAllocateAlpha($destImg, $red, $green, $blue, $alpha); + imageSetPixel($destImg, $x + $destX, $y + $destY, $color); + } + } + } + } + } + } + + /** + * Merge two image var + * + * @param resource $destinationImage + * @param resource $sourceImage + * @param integer $destinationPosX + * @param integer $destinationPosY + * @param integer $sourcePosX + * @param integer $sourcePosY + */ + public static function mergeTwoImages(&$destinationImage, $sourceImage, $destinationPosX = 0, $destinationPosY = 0, $sourcePosX = 0, $sourcePosY = 0) + { + imageCopy($destinationImage, $sourceImage, $destinationPosX, $destinationPosY, $sourcePosX, $sourcePosY, imageSX($sourceImage), imageSY($sourceImage)); + } } \ No newline at end of file diff --git a/PHPImageWorkshop/Exception/ImageWorkshopBaseException.php b/PHPImageWorkshop/Exception/ImageWorkshopBaseException.php index 81ed653..e1925f5 100644 --- a/PHPImageWorkshop/Exception/ImageWorkshopBaseException.php +++ b/PHPImageWorkshop/Exception/ImageWorkshopBaseException.php @@ -1,38 +1,38 @@ -code}]: {$this->message}\n"; - } +code}]: {$this->message}\n"; + } } \ No newline at end of file diff --git a/PHPImageWorkshop/Exception/ImageWorkshopException.php b/PHPImageWorkshop/Exception/ImageWorkshopException.php index c2efa97..7663c93 100644 --- a/PHPImageWorkshop/Exception/ImageWorkshopException.php +++ b/PHPImageWorkshop/Exception/ImageWorkshopException.php @@ -1,22 +1,22 @@ -write($text, $fontPath, $fontSize, $fontColor, $textDimensions['left'], $textDimensions['top'], $textRotation); - - return $layer; - } - - /** - * Initialize a new virgin layer - * - * @param integer $width - * @param integer $height - * @param string $backgroundColor - * - * @return ImageWorkshopLayer - */ - public static function initVirginLayer($width = 100, $height = 100, $backgroundColor = null) - { - $opacity = 0; - - if (!$backgroundColor || $backgroundColor == 'transparent') { - $opacity = 127; - $backgroundColor = 'ffffff'; - } - - return new ImageWorkshopLayer(ImageWorkshopLib::generateImage($width, $height, $backgroundColor, $opacity)); - } - - /** - * Initialize a layer from a resource image var - * - * @param \resource $image - * - * @return ImageWorkshopLayer - */ - public static function initFromResourceVar($image) - { - return new ImageWorkshopLayer($image); - } - - /** - * Initialize a layer from a string (obtains with file_get_contents, cURL...) - * - * This not recommanded to initialize JPEG string with this method, GD displays bugs ! - * - * @param string $imageString - * - * @return ImageWorkshopLayer - */ - public static function initFromString($imageString) - { - if (!$image = @imageCreateFromString($imageString)) { - throw new ImageWorkshopException('Can\'t generate an image from the given string.', static::ERROR_CREATE_IMAGE_FROM_STRING); - } - - return new ImageWorkshopLayer($image); - } +write($text, $fontPath, $fontSize, $fontColor, $textDimensions['left'], $textDimensions['top'], $textRotation); + + return $layer; + } + + /** + * Initialize a new virgin layer + * + * @param integer $width + * @param integer $height + * @param string $backgroundColor + * + * @return ImageWorkshopLayer + */ + public static function initVirginLayer($width = 100, $height = 100, $backgroundColor = null) + { + $opacity = 0; + + if (!$backgroundColor || $backgroundColor == 'transparent') { + $opacity = 127; + $backgroundColor = 'ffffff'; + } + + return new ImageWorkshopLayer(ImageWorkshopLib::generateImage($width, $height, $backgroundColor, $opacity)); + } + + /** + * Initialize a layer from a resource image var + * + * @param \resource $image + * + * @return ImageWorkshopLayer + */ + public static function initFromResourceVar($image) + { + return new ImageWorkshopLayer($image); + } + + /** + * Initialize a layer from a string (obtains with file_get_contents, cURL...) + * + * This not recommanded to initialize JPEG string with this method, GD displays bugs ! + * + * @param string $imageString + * + * @return ImageWorkshopLayer + */ + public static function initFromString($imageString) + { + if (!$image = @imageCreateFromString($imageString)) { + throw new ImageWorkshopException('Can\'t generate an image from the given string.', static::ERROR_CREATE_IMAGE_FROM_STRING); + } + + return new ImageWorkshopLayer($image); + } } \ No newline at end of file diff --git a/config.inc.php b/config.inc.php index 0251c1a..b6284cc 100644 --- a/config.inc.php +++ b/config.inc.php @@ -1,8 +1,10 @@ -get('/photos/thumbnail/:imageID(/:createImgTag)', function ($imageID, $createImgTag = 0) use ($app) { - $mysqlconnetion = new MysqlClass; - - $retObj = $mysqlconnetion->queryToObject("select type_format, image_thumbnail from immagini where id=" . $imageID, false); - $mysqlconnetion->disconnetti(); - - if($createImgTag) - echo ''; - else - { - $app->contentType($retObj["type_format"]); - echo $retObj['image_thumbnail']; - } -}); - -$app->get('/photos/:imageID(/:createImgTag)', function ($imageID, $createImgTag = 0) use ($app) { - $mysqlconnetion = new MysqlClass; - - $retObj = $mysqlconnetion->queryToObject("select type_format, image from immagini where id=" . $imageID, false); - $mysqlconnetion->disconnetti(); - - if($createImgTag) - echo ''; -}); - -$app->put('/photos/publish/:imageID', function ($imageID) use ($app) { - $mysqlconnetion = new MysqlClass; - - $query = "update immagini set published = 1, published_date = NOW() where ProfiloID = " . $imageID; - $mysqlconnetion->disconnetti(); - $mysqlconnetion->insertRecord($query); - $mysqlconnetion->disconnetti(); -}); - -$app->post('/photos', function () use ($app) { - $idRicette = $app->request()->post('ricetta_id'); - $profileID = $app->request()->post('keyStore'); - $imageFileName = $_FILES['image']["tmp_name"]; - - $layer = ImageWorkshop::initFromPath($imageFileName); - $layer->resizeByLargestSideInPixel(640, true); - - $layer->save(dirname($imageFileName), basename($imageFileName)); - - $imgData = addslashes(file_get_contents($imageFileName)); - - $layer->resizeByLargestSideInPixel(300, true); - - $layer->save(dirname($imageFileName), basename($imageFileName)); - - $ThumbImageData = addslashes(file_get_contents($imageFileName)); - -// istanza della classe - $mysqlconnetion = new MysqlClass; -//$mysqlconneti on->connetti(); - $query = "insert into immagini(id_ricette, type_format, image_thumbnail, image, from_profile_id, uploaded_date) " . - "values(" . $idRicette . ", '" . image_type_to_mime_type($image->image_type) . - "', '" . $ThumbImageData . "', '" . $imgData . "', '" . $profileID . "', NOW())"; - $newID = $mysqlconnetion->insertRecord($query); - $mysqlconnetion->disconnetti(); - - echo $newID; -}); - -$app->put('/photos/:imageID', function ($imageID) use ($app) { - $imageFileName = $_FILES['image']["tmp_name"]; - - $layer = ImageWorkshop::initFromPath($imageFileName); - $layer->resizeByLargestSideInPixel(640, true); - - $layer->save(dirname($imageFileName), basename($imageFileName)); - - $imgData = addslashes(file_get_contents($imageFileName)); - - $layer->resizeByLargestSideInPixel(300, true); - - $layer->save(dirname($imageFileName), basename($imageFileName)); - - $ThumbImageData = addslashes(file_get_contents($imageFileName)); - -// istanza della classe - $mysqlconnetion = new MysqlClass; -//$mysqlconneti on->connetti(); - $query = "update immagini set (type_format = '" . image_type_to_mime_type($image->image_type) . "', " . - "image_thumbnail = '" . $ThumbImageData . "', " . - "image = '" . $imgData . "' where id=" . $imageID; - - $newID = $mysqlconnetion->insertRecord($query); - $mysqlconnetion->disconnetti(); - - return $newID; -}); +get('/photos/thumbnail/:imageID(/:createImgTag)', function ($imageID, $createImgTag = 0) use ($app, $dirRicetteDropBox) { + $mysqlconnetion = new MysqlClass; + + $retObj = $mysqlconnetion->queryToObject("select type_format, id_ricette from immagini where id=" . $imageID, false); + $mysqlconnetion->disconnetti(); + + $ext = ""; + if ($retObj["type_format"] == "image/jpeg") { + $ext = "jpg"; + } else if ($retObj["type_format"] == "image/png") { + $ext = "png"; + } + + $folder = $dirRicetteDropBox . "/" . $retObj["id_ricette"]; + + $imageFileName = $imageID . "_thumb_ricetta." . $ext; + + $dropBoxObj = new myDropBox(); + + if ($createImgTag) { + echo ''; + } +}); + +$app->get('/photos/:imageID(/:createImgTag)', function ($imageID, $createImgTag = 0) use ($app, $dirRicetteDropBox) { + $mysqlconnetion = new MysqlClass; + + $retObj = $mysqlconnetion->queryToObject("select type_format, id_ricette from immagini where id=" . $imageID, false); + $mysqlconnetion->disconnetti(); + $ext = ""; + if ($retObj["type_format"] == "image/jpeg") { + $ext = "jpg"; + } else if ($retObj["type_format"] == "image/png") { + $ext = "png"; + } + + $folder = $dirRicetteDropBox . "/" . $retObj["id_ricette"]; + + $imageFileName = $imageID . "_full_ricetta." . $ext; + + $dropBoxObj = new myDropBox(); + + if ($createImgTag) { + echo ''; + } +}); + +$app->put('/photos/publish/:imageID', function ($imageID) use ($app) { + $mysqlconnetion = new MysqlClass; + + $query = "update immagini set published = 1, published_date = NOW() where id = " . $imageID; + + $mysqlconnetion->insertRecord($query); + $mysqlconnetion->disconnetti(); +}); + +$app->post('/photos', function () use ($app, $dirRicetteDropBox) { + $idRicette = $app->request()->post('ricetta_id'); + $profileID = $app->request()->post('keyStore'); + $tmpFileName = $_FILES['image']["tmp_name"]; + $layer = ImageWorkshop::initFromPath($tmpFileName); + // istanza della classe + $mysqlconnetion = new MysqlClass; + //$mysqlconneti on->connetti(); + $query = "insert into immagini(id_ricette, type_format, from_profile_id, uploaded_date) " . + "values(" . $idRicette . ", '" . image_type_to_mime_type(exif_imagetype($tmpFileName)) . + "', '" . $profileID . "', NOW())"; + $newID = $mysqlconnetion->insertRecord($query); + $ext = image_type_to_extension(exif_imagetype($tmpFileName), FALSE); + + $imageFileName = $newID . "_full_ricetta." . $ext; + + $thumbFileName = $newID . "_thumb_ricetta." . $ext; + + $layer->resizeByLargestSideInPixel(640, true); + + $layer->save(dirname($tmpFileName), $imageFileName); + + $layer->resizeByLargestSideInPixel(300, true); + + $layer->save(dirname($tmpFileName), $thumbFileName); + + $dropBoxObj = new myDropBox(); + + $folder = $dirRicetteDropBox . "/" . $idRicette; + + try { + $dropBoxObj->CreateFolder($folder); + } catch (DropboxException $ex) { + + } + $fullPath = dirname($tmpFileName) . "/" . $imageFileName; + echo $fullPath . "\n"; + $thumbPath = dirname($tmpFileName) . "/" . $thumbFileName; + echo $thumbPath . "\n"; + $dropBoxObj->UploadFile($fullPath, $folder . "/" . $imageFileName); + + $dropBoxObj->UploadFile($thumbPath, $folder . "/" . $thumbFileName); + + $mysqlconnetion->disconnetti(); + + echo $newID; +}); + +$app->put('/photos/:imageID', function ($imageID) use ($app, $dirRicetteDropBox) { + $tmpFileName = $_FILES['image']["tmp_name"]; + $layer = ImageWorkshop::initFromPath($tmpFileName); +// istanza della classe + $mysqlconnetion = new MysqlClass; +//$mysqlconneti on->connetti(); + $query = "update immagini set (type_format = '" . image_type_to_mime_type(exif_imagetype($tmpFileName)) . "', " . + " where id=" . $imageID; + + $newID = $mysqlconnetion->insertRecord($query); + + $imageFileName = $imageID . "_full_ricetta"; + + $thumbFileName = $imageID . "_thumb_ricetta"; + + $layer->resizeByLargestSideInPixel(640, true); + + $layer->save(dirname($tmpFileName), $imageFileName); + + $layer->resizeByLargestSideInPixel(300, true); + + $layer->save(dirname($tmpFileName), $thumbFileName); + + $dropBoxObj = new myDropBox(); + + $folder = $dirRicetteDropBox . "/" . $idRicette; + + $dropBoxObj->UploadFile(dirname($tmpFileName) . DIRECTORY_SEPARATOR . $imageFileName, $folder . "\\" . $imageFileName); + + $dropBoxObj->UploadFile(dirname($tmpFileName) . DIRECTORY_SEPARATOR . $thumbFileName, $folder . "\\" . $thumbFileName); + + $mysqlconnetion->disconnetti(); + + return $newID; +}); diff --git a/include.php b/include.php index b400eb4..aae1e0e 100644 --- a/include.php +++ b/include.php @@ -14,7 +14,10 @@ $app = new \Slim\Slim(); $app->hook('slim.before.router', function () use ($app, $allowedHost) { $currentRefererRequest = $app->request()->getReferer(); - $currentRefererRequest = substr(substr($currentRefererRequest, 7), 0, strpos(substr($currentRefererRequest, 7), '/')); + $currentRefererRequest = substr($currentRefererRequest, 7); //Senza http:// + $indexDoublePoint = strpos($currentRefererRequest, ':'); + $indexFirstSlash = strpos($currentRefererRequest, '/'); + $currentRefererRequest = substr($currentRefererRequest, 0, $indexDoublePoint > 0 && $indexDoublePoint < $indexFirstSlash ? $indexDoublePoint : $indexFirstSlash ); if(!in_array($currentRefererRequest, $allowedHost)) { $app->halt(500, "Generic error occurred"); diff --git a/management.php b/management.php index e4165ae..81a0767 100644 --- a/management.php +++ b/management.php @@ -1,165 +1,165 @@ -get('/categories', function () use ($app) { - $callbackFn = $app->request()->get('callback'); - $mysqlconnetion = new MysqlClass; - //$mysqlconneti on->connetti(); - $retObj = $mysqlconnetion->queryToObject("select ID as category_id, NAME as name from categorie order by name"); - $mysqlconnetion->disconnetti(); - - returnJsonWithDecode($app, $callbackFn, $retObj); -}); - -$app->get('/typeingredients', function () use ($app) { - $callbackFn = $app->request()->get('callback'); - $mysqlconnetion = new MysqlClass; - //$mysqlconnetion->connetti(); - $retObj = $mysqlconnetion->queryToObject("select ID as tipo_ingredienti_id, name from tipo_ingredienti order by name"); - $mysqlconnetion->disconnetti(); - - returnJsonWithDecode($app, $callbackFn, $retObj); -}); - -$app->get('/typeqtys', function () use ($app) { - $callbackFn = $app->request()->get('callback'); - $mysqlconnetion = new MysqlClass; - //$mysqlconnetion->connetti(); - $retObj = $mysqlconnetion->queryToObject("select ID as tipo_quantita_id, name from tipo_quantita"); - $mysqlconnetion->disconnetti(); - - returnJsonWithDecode($app, $callbackFn, $retObj); -}); - -$app->get('/categoryitems/:catID', function ($categoryID) use ($app) { - $callbackFn = $app->request()->get('callback'); - $mysqlconnetion = new MysqlClass; - //$mysqlconnetion->connetti(); - $query = "select ID as ricetta_id, titolo, autore, valutazione, difficolta from ricette where ID_CATEGORIA = " . $categoryID . " order by titolo, autore"; - $retObj = $mysqlconnetion->queryToObject($query); - $mysqlconnetion->disconnetti(); - - returnJson($app, $callbackFn, $retObj); -}); - -$app->get('/ricetta/body/:itemID', function ($itemID) use ($app) { - $callbackFn = $app->request()->get('callback'); - // istanza della classe - $mysqlconnetion = new MysqlClass; - $query = "SELECT id_categoria, categorie.name AS categoria_name, ricette.ID AS ricetta_id, titolo, procedimento, autore, link_fonte, link_youtube, valutazione, difficolta FROM ricette INNER JOIN categorie ON categorie.ID = ricette.id_categoria WHERE ricette.ID = " . $itemID; - $retObj = $mysqlconnetion->queryToObject($query); - - $query2 = "select ingredienti.id_tipo_ingredienti, tipo_ingredienti.name as nome_ingrediente, quantita, ingredienti.id_tipo_quantita, tipo_quantita.Name as unita, note, posizione from ingredienti " . - "inner join tipo_ingredienti on ingredienti.ID_TIPO_INGREDIENTI = tipo_ingredienti.ID " . - "left outer join tipo_quantita on ingredienti.ID_TIPO_QUANTITA = tipo_quantita.ID " . - "where ingredienti.ID_RICETTE = " . $itemID . " order by ingredienti.posizione"; - - $retObj2 = $mysqlconnetion->queryToObject($query2); - - $retObj[0]["titolo"] = html_entity_decode($retObj[0]["titolo"],ENT_COMPAT | ENT_HTML401,'ISO-8859-1'); - $retObj[0]["procedimento"] = html_entity_decode($retObj[0]["procedimento"],ENT_COMPAT | ENT_HTML401,'ISO-8859-1'); - $retObj[0]["ingredienti"] = $retObj2; - - $mysqlconnetion->disconnetti(); - returnJson($app, $callbackFn, $retObj); -}); - -$app->post('/typeingredients', function () use ($app) { - $callbackFn = $app->request()->get('callback'); - $json_data_body = json_decode($app->request()->post('bodydata')); - $mysqlconnetion = new MysqlClass; - //$mysqlconnetion->connetti(); - $query = "insert into tipo_ingredienti(Name) values ('" . $json_data_body->name . "')"; - - $retNewID = $mysqlconnetion->insertRecord($query); - $mysqlconnetion->disconnetti(); - - returnJson($app, $callbackFn, $retNewID); -}); - -$app->post('/ricetta/body', function () use ($app) { - $callbackFn = $app->request()->get('callback'); - $json_data_body = json_decode($app->request()->post('bodydata')); - $retValue["result"] = true; - $retValue["message"] = ""; - $mysqlconnetion = new MysqlClass; - // istanza della classe - try { - $retNewID = 0; - if ($json_data_body->ricettaID != "") { - $query = "update ricette SET ID_CATEGORIA = " . $json_data_body->categoria_id . - ", titolo = '" . htmlentities($json_data_body->titolo, null, "UTF-8") . - "', procedimento = '" . str_replace("'", "''", htmlentities($json_data_body->preparazione, null, "UTF-8")) . - "', autore = '" . str_replace("'", "''", $json_data_body->autore) . - "', link_fonte = '" . $json_data_body->linkFonte . - "', Link_youtube = '" . $json_data_body->linkVideo . - "', Difficolta = '" . $json_data_body->difficolta . - "' where ID = " . $json_data_body->ricettaID; - - $mysqlconnetion->executeQuery($query); - $queryDelete = "DELETE FROM ingredienti where ID_RICETTE = " . $json_data_body->ricettaID; - $mysqlconnetion->executeQuery($queryDelete); - $retNewID = $json_data_body->ricettaID; - } else { - - $query = "insert into ricette(ID_CATEGORIA, titolo, procedimento, autore, link_fonte, Link_youtube,Difficolta) values (" . - $json_data_body->categoria_id . ",'" . htmlentities($json_data_body->titolo, null, "UTF-8") . "','" . str_replace("'", "''", htmlentities($json_data_body->preparazione, null, "UTF-8")) . - "','" . str_replace("'", "''", $json_data_body->autore) . "','" . - $json_data_body->linkFonte . "','" . $json_data_body->linkVideo . "', " . $json_data_body->difficolta . ")"; - - $retNewID = $mysqlconnetion->insertRecord($query); - } - - $pos = 0; - foreach ($json_data_body->ingredienti as $arr) { - $note = ""; - if ($arr->note != "") { - $note = str_replace("'", "''", htmlentities($arr->note)); - } - - $query = "insert into ingredienti(ID_TIPO_INGREDIENTI, ID_RICETTE, Quantita, ID_TIPO_QUANTITA, Note, Posizione) values (" . - $arr->ingrediente_id . "," . $retNewID . "," . ($arr->quantita == "" ? "0" : $arr->quantita) . "," . ($arr->tipo_quantita_id == "" ? "NULL" : $arr->tipo_quantita_id) . ",'" . $note . "'," . $pos . ")"; - - $mysqlconnetion->insertRecord($query); - $pos = $pos + 1; - } - - $retValue["message"] = "Ricetta inserita con successo"; - } catch (Exception $e) { - $retValue["message"] = $e->getMessage(); - } - - $mysqlconnetion->disconnetti(); - - returnJson($app, $callbackFn, $retValue); -}); - -$app->get('/photos/', function () use ($app) { - $callbackFn = $app->request()->get('callback'); - - $query = "SELECT * from ( SELECT id as ricetta_id, `titolo`,`autore`, ". - " (select COUNT(*) from immagini where immagini.id_ricette = `ricette`.id) as num_img,". - " (select COUNT(*) from immagini where immagini.id_ricette = `ricette`.id and immagini.published = 1) as num_img_pub". - " FROM `ricette`". - " ) as tmp". - " WHERE tmp.num_img> 0"; - - $mysqlconnetion = new MysqlClass; - //$mysqlconnetion->connetti(); - $retObj = $mysqlconnetion->queryToObject($query); - $mysqlconnetion->disconnetti(); - returnJson($app, $callbackFn, $retObj); -}); - -$app->get('/ricetta/:itemID/photos', function ($itemID) use ($app) { - $callbackFn = $app->request()->get('callback'); - - $query = "SELECT id as id_photo, type_format, from_profile_id, uploaded_date, profilo.Name as profile_name, published from immagini" . - " INNER JOIN profilo ON profilo.ProfiloID = immagini.from_profile_id". - " WHERE id_ricette = " . $itemID; - - $mysqlconnetion = new MysqlClass; - //$mysqlconnetion->connetti(); - $retObj = $mysqlconnetion->queryToObject($query); - $mysqlconnetion->disconnetti(); - returnJson($app, $callbackFn, $retObj); +get('/categories', function () use ($app) { + $callbackFn = $app->request()->get('callback'); + $mysqlconnetion = new MysqlClass; + //$mysqlconneti on->connetti(); + $retObj = $mysqlconnetion->queryToObject("select ID as category_id, NAME as name from categorie order by name"); + $mysqlconnetion->disconnetti(); + + returnJsonWithDecode($app, $callbackFn, $retObj); +}); + +$app->get('/typeingredients', function () use ($app) { + $callbackFn = $app->request()->get('callback'); + $mysqlconnetion = new MysqlClass; + //$mysqlconnetion->connetti(); + $retObj = $mysqlconnetion->queryToObject("select ID as tipo_ingredienti_id, name from tipo_ingredienti order by name"); + $mysqlconnetion->disconnetti(); + + returnJsonWithDecode($app, $callbackFn, $retObj); +}); + +$app->get('/typeqtys', function () use ($app) { + $callbackFn = $app->request()->get('callback'); + $mysqlconnetion = new MysqlClass; + //$mysqlconnetion->connetti(); + $retObj = $mysqlconnetion->queryToObject("select ID as tipo_quantita_id, name from tipo_quantita"); + $mysqlconnetion->disconnetti(); + + returnJsonWithDecode($app, $callbackFn, $retObj); +}); + +$app->get('/ricette/:catID', function ($categoryID) use ($app) { + $callbackFn = $app->request()->get('callback'); + $mysqlconnetion = new MysqlClass; + //$mysqlconnetion->connetti(); + $query = "select ID as ricetta_id, titolo, autore, valutazione, difficolta from ricette where ID_CATEGORIA = " . $categoryID . " order by titolo, autore"; + $retObj = $mysqlconnetion->queryToObject($query); + $mysqlconnetion->disconnetti(); + + returnJson($app, $callbackFn, $retObj); +}); + +$app->get('/ricetta/body/:itemID', function ($itemID) use ($app) { + $callbackFn = $app->request()->get('callback'); + // istanza della classe + $mysqlconnetion = new MysqlClass; + $query = "SELECT id_categoria, categorie.name AS categoria_name, ricette.ID AS ricetta_id, titolo, procedimento, autore, link_fonte, link_youtube, valutazione, difficolta FROM ricette INNER JOIN categorie ON categorie.ID = ricette.id_categoria WHERE ricette.ID = " . $itemID; + $retObj = $mysqlconnetion->queryToObject($query); + + $query2 = "select ingredienti.id_tipo_ingredienti, tipo_ingredienti.name as nome_ingrediente, quantita, ingredienti.id_tipo_quantita, tipo_quantita.Name as unita, note, posizione from ingredienti " . + "inner join tipo_ingredienti on ingredienti.ID_TIPO_INGREDIENTI = tipo_ingredienti.ID " . + "left outer join tipo_quantita on ingredienti.ID_TIPO_QUANTITA = tipo_quantita.ID " . + "where ingredienti.ID_RICETTE = " . $itemID . " order by ingredienti.posizione"; + + $retObj2 = $mysqlconnetion->queryToObject($query2); + + $retObj[0]["titolo"] = html_entity_decode($retObj[0]["titolo"],ENT_COMPAT | ENT_HTML401,'ISO-8859-1'); + $retObj[0]["procedimento"] = html_entity_decode($retObj[0]["procedimento"],ENT_COMPAT | ENT_HTML401,'ISO-8859-1'); + $retObj[0]["ingredienti"] = $retObj2; + + $mysqlconnetion->disconnetti(); + returnJson($app, $callbackFn, $retObj); +}); + +$app->post('/typeingredients', function () use ($app) { + $callbackFn = $app->request()->get('callback'); + $json_data_body = json_decode($app->request()->post('bodydata')); + $mysqlconnetion = new MysqlClass; + //$mysqlconnetion->connetti(); + $query = "insert into tipo_ingredienti(Name) values ('" . $json_data_body->name . "')"; + + $retNewID = $mysqlconnetion->insertRecord($query); + $mysqlconnetion->disconnetti(); + + returnJson($app, $callbackFn, $retNewID); +}); + +$app->post('/ricetta/body', function () use ($app) { + $callbackFn = $app->request()->get('callback'); + $json_data_body = json_decode($app->request()->post('bodydata')); + $retValue["result"] = true; + $retValue["message"] = ""; + $mysqlconnetion = new MysqlClass; + // istanza della classe + try { + $retNewID = 0; + if ($json_data_body->ricettaID != "") { + $query = "update ricette SET ID_CATEGORIA = " . $json_data_body->categoria_id . + ", titolo = '" . htmlentities($json_data_body->titolo, null, "UTF-8") . + "', procedimento = '" . str_replace("'", "''", htmlentities($json_data_body->preparazione, null, "UTF-8")) . + "', autore = '" . str_replace("'", "''", $json_data_body->autore) . + "', link_fonte = '" . $json_data_body->linkFonte . + "', Link_youtube = '" . $json_data_body->linkVideo . + "', Difficolta = '" . $json_data_body->difficolta . + "' where ID = " . $json_data_body->ricettaID; + + $mysqlconnetion->executeQuery($query); + $queryDelete = "DELETE FROM ingredienti where ID_RICETTE = " . $json_data_body->ricettaID; + $mysqlconnetion->executeQuery($queryDelete); + $retNewID = $json_data_body->ricettaID; + } else { + + $query = "insert into ricette(ID_CATEGORIA, titolo, procedimento, autore, link_fonte, Link_youtube,Difficolta) values (" . + $json_data_body->categoria_id . ",'" . htmlentities($json_data_body->titolo, null, "UTF-8") . "','" . str_replace("'", "''", htmlentities($json_data_body->preparazione, null, "UTF-8")) . + "','" . str_replace("'", "''", $json_data_body->autore) . "','" . + $json_data_body->linkFonte . "','" . $json_data_body->linkVideo . "', " . $json_data_body->difficolta . ")"; + + $retNewID = $mysqlconnetion->insertRecord($query); + } + + $pos = 0; + foreach ($json_data_body->ingredienti as $arr) { + $note = ""; + if ($arr->note != "") { + $note = str_replace("'", "''", htmlentities($arr->note)); + } + + $query = "insert into ingredienti(ID_TIPO_INGREDIENTI, ID_RICETTE, Quantita, ID_TIPO_QUANTITA, Note, Posizione) values (" . + $arr->ingrediente_id . "," . $retNewID . "," . ($arr->quantita == "" ? "0" : $arr->quantita) . "," . ($arr->tipo_quantita_id == "" ? "NULL" : $arr->tipo_quantita_id) . ",'" . $note . "'," . $pos . ")"; + + $mysqlconnetion->insertRecord($query); + $pos = $pos + 1; + } + + $retValue["message"] = "Ricetta inserita con successo"; + } catch (Exception $e) { + $retValue["message"] = $e->getMessage(); + } + + $mysqlconnetion->disconnetti(); + + returnJson($app, $callbackFn, $retValue); +}); + +$app->get('/photos/', function () use ($app) { + $callbackFn = $app->request()->get('callback'); + + $query = "SELECT * from ( SELECT id as ricetta_id, `titolo`,`autore`, ". + " (select COUNT(*) from immagini where immagini.id_ricette = `ricette`.id) as num_img,". + " (select COUNT(*) from immagini where immagini.id_ricette = `ricette`.id and immagini.published = 1) as num_img_pub". + " FROM `ricette`". + " ) as tmp". + " WHERE tmp.num_img> 0"; + + $mysqlconnetion = new MysqlClass; + //$mysqlconnetion->connetti(); + $retObj = $mysqlconnetion->queryToObject($query); + $mysqlconnetion->disconnetti(); + returnJson($app, $callbackFn, $retObj); +}); + +$app->get('/ricetta/:itemID/photos', function ($itemID) use ($app) { + $callbackFn = $app->request()->get('callback'); + + $query = "SELECT id as id_photo, type_format, from_profile_id, uploaded_date, profilo.Name as profile_name, published from immagini" . + " INNER JOIN profilo ON profilo.ProfiloID = immagini.from_profile_id". + " WHERE id_ricette = " . $itemID; + + $mysqlconnetion = new MysqlClass; + //$mysqlconnetion->connetti(); + $retObj = $mysqlconnetion->queryToObject($query); + $mysqlconnetion->disconnetti(); + returnJson($app, $callbackFn, $retObj); }); \ No newline at end of file diff --git a/mdbTester.php b/mdbTester.php new file mode 100644 index 0000000..229296b --- /dev/null +++ b/mdbTester.php @@ -0,0 +1,53 @@ +GetLink($folder . "/" . $imageFileName); + +return; +*/ +$layer = ImageWorkshop::initFromPath($tmpFileName); + +echo $layer->getImage()->image_type; +return; + +$layer->resizeByLargestSideInPixel(640, true); + +$layer->save(dirname($tmpFileName), $imageFileName); + +$imgData = addslashes(file_get_contents($tmpFileName)); + +$layer->resizeByLargestSideInPixel(300, true); + +$layer->save(dirname($tmpFileName), $thumbFileName); + +try { + $dropBoxObj->CreateFolder($folder); +} catch (DropboxException $ex) { + +} + +$dropBoxObj->UploadFile(dirname($tmpFileName) . "/" . $imageFileName, $folder . "/" . $imageFileName); + +$dropBoxObj->UploadFile(dirname($tmpFileName) . "/" . $thumbFileName, $folder . "/" . $thumbFileName); \ No newline at end of file diff --git a/myDropBoxObj.php b/myDropBoxObj.php new file mode 100644 index 0000000..f120e43 --- /dev/null +++ b/myDropBoxObj.php @@ -0,0 +1,78 @@ +dropbox = new DropboxClient( + array( + 'app_key' => "ft0zodv89xx804e", + 'app_secret' => "ut43sn7m9wufy3s", + 'app_full_access' => true + ), 'it'); + $this->internalLoad(); + } + + protected function internalLoad() { + // first try to load existing access token + $access_token = $this->load_token("access"); + if (!empty($access_token)) { + $this->dropbox->SetAccessToken($access_token); + echo "loaded access token:"; + print_r($access_token); + } elseif (!empty($_GET['auth_callback'])) { // are we coming from dropbox's auth page? + // then load our previosly created request token + $request_token = $this->load_token($_GET['oauth_token']); + if (empty($request_token)) + die('Request token not found!'); + // get & store access token, the request token is not needed anymore + $access_token = $this->dropbox->GetAccessToken($request_token); + $this->store_token($access_token, "access"); + $this->delete_token($_GET['oauth_token']); + } + // checks if access token is required + if (!$this->dropbox->IsAuthorized()) { + // redirect user to dropbox auth page + $return_url = "http://" . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . "?auth_callback=1"; + $auth_url = $this->dropbox->BuildAuthorizeUrl($return_url); + $request_token = $this->dropbox->GetRequestToken(); + $this->store_token($request_token, $request_token['t']); + die("Authentication required. Click here."); + } + } + + public function UploadFile($fileToUpload, $dropBoxPath) { + $ret = $this->dropbox->UploadFile($fileToUpload, $dropBoxPath); + return true; + } + + public function GetLink($dropBoxPathFile) { + return $this->dropbox->GetLink($dropBoxPathFile, false, false); + } + + public function CreateFolder($dropBoxPath) { + $ret = $this->dropbox->CreateFolder($dropBoxPath); + return true; + } + + private function store_token($token, $name) { + if (!file_put_contents("tokens/$name.token", serialize($token))) + die('
Could not store token! Make sure that the directory `tokens` exists and is writable!'); + } + + private function load_token($name) { + if (!file_exists("tokens/$name.token")) + return null; + return @unserialize(@file_get_contents("tokens/$name.token")); + } + + private function delete_token($name) { + @unlink("tokens/$name.token"); + } + +} diff --git a/nbproject/private/config.properties b/nbproject/private/config.properties new file mode 100644 index 0000000..e69de29 diff --git a/nbproject/private/private.properties b/nbproject/private/private.properties new file mode 100644 index 0000000..49ccdf8 --- /dev/null +++ b/nbproject/private/private.properties @@ -0,0 +1,9 @@ +browser.id=Chrome.INTEGRATED +copy.src.files=false +copy.src.on.open=false +copy.src.target= +hostname=localhost +port=8888 +router=mdbTester.php +run.as=INTERNAL +url=http://localhost:8888/ diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml new file mode 100644 index 0000000..284eeec --- /dev/null +++ b/nbproject/private/private.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/nbproject/project.properties b/nbproject/project.properties new file mode 100644 index 0000000..6df3cbb --- /dev/null +++ b/nbproject/project.properties @@ -0,0 +1,7 @@ +include.path=${php.global.include.path} +php.version=PHP_53 +source.encoding=UTF-8 +src.dir=. +tags.asp=false +tags.short=false +web.root=. diff --git a/nbproject/project.xml b/nbproject/project.xml new file mode 100644 index 0000000..aa3be94 --- /dev/null +++ b/nbproject/project.xml @@ -0,0 +1,9 @@ + + + org.netbeans.modules.php.project + + + Service + + + diff --git a/profile.php b/profile.php index 43b2044..b9e3369 100644 --- a/profile.php +++ b/profile.php @@ -1,111 +1,111 @@ -get('/profile/:keyStore/ricetta/:ricetta_id', function ($keyStore, $ricetta_id) use ($app) { - $callbackFn = $app->request()->get('callback'); - $mysqlconnetion = new MysqlClass; - $query = "select COUNT(*) as Exist FROM blocco_note where ricetta_id = " . $ricetta_id . " AND ProfiloID = '" . $keyStore . "'"; - $retObj = $mysqlconnetion->queryToObject($query); - $mysqlconnetion->disconnetti(); - - returnJson($app, $callbackFn, $retObj[0]["Exist"]); -}); - -$app->post('/profile/ricetta', function () use ($app) { - $callbackFn = $app->request()->get('callback'); - $json_data_body = json_decode($app->request()->post('dataPair')); - $mysqlconnetion = new MysqlClass; - $query = "insert into blocco_note(ricetta_id, ProfiloID) values (" . $json_data_body->ricetta_id . ", '" . $json_data_body->keyStore . "')"; - $retNewID = $mysqlconnetion->insertRecord($query); - $mysqlconnetion->disconnetti(); - - returnJson($app, $callbackFn, $retNewID); -}); - -$app->delete('/profile/:keyStore/ricetta/:ricetta_id', function ($keyStore, $ricetta_id) use ($app) { - //$callbackFn = $app->request()->params('callback'); - $mysqlconnetion = new MysqlClass; - $query = "delete from blocco_note where ricetta_id = " . $ricetta_id . " AND ProfiloID = '" . $keyStore . "'"; - - $retNewID = $mysqlconnetion->insertRecord($query); - $mysqlconnetion->disconnetti(); - - echo $retNewID; - //returnJson($app, $callbackFn, $retNewID); -}); - -$app->delete('/profile/:keyStore/ricette', function ($keyStore) use ($app) { - $callbackFn = $app->request()->get('callback'); - $mysqlconnetion = new MysqlClass; - $query = "delete from blocco_note where ProfiloID = '" . $keyStore . "'"; - - $retNewID = $mysqlconnetion->insertRecord($query); - $mysqlconnetion->disconnetti(); - - returnJson($app, $callbackFn, $retNewID); -}); - -$app->get('/profile/:keyStore/ricette', function ($keyStore) use ($app) { - $callbackFn = $app->request()->get('callback'); - $mysqlconnetion = new MysqlClass; - $query = "select ID as ricetta_id, titolo, autore, valutazione, difficolta from ricette" . - " INNER JOIN blocco_note ON blocco_note.ricetta_id = ricette.id" . - " where blocco_note.ProfiloID = '" . $keyStore . "' order by titolo, autore"; - $retObj = $mysqlconnetion->queryToObject($query); - $mysqlconnetion->disconnetti(); - - foreach ($retObj as $ele) { - $ele["titolo"] = html_entity_decode($ele["titolo"]); - } - - returnJson($app, $callbackFn, $retObj); -}); - -$app->get('/profile/:keyStore', function ($keyStore) use ($app) { - $callbackFn = $app->request()->get('callback'); - $mysqlconnetion = new MysqlClass; - $query = "select ProfiloID, TipoAccesso, RisultatiRicerca, TemaUI, Name, Gender, 0 as NumRicette from profilo" . - " where ProfiloID = '" . $keyStore . "'"; - $retObj = $mysqlconnetion->queryToObject($query); - - $query = "update profilo set PenultimoAccesso = UltimoAccesso, UltimoAccesso = NOW() where ProfiloID = '" . $keyStore . "'"; - $mysqlconnetion->insertRecord($query); - - $query = "SELECT COUNT( * ) as NumRicette FROM ricette WHERE data_creazione > ( SELECT PenultimoAccesso FROM profilo " . - "WHERE `ProfiloID` = '" . $keyStore . "' )"; - - $retObj2 = $mysqlconnetion->queryToObject($query); - - $retObj[0]["NumRicette"] = $retObj2[0]["NumRicette"]; - - returnJson($app, $callbackFn, $retObj); -}); - -$app->post('/profile', function () use ($app) { - $callbackFn = $app->request()->get('callback'); - $json_data_body = json_decode($app->request()->post('dataPair')); - $mysqlconnetion = new MysqlClass; - $query = "insert into profilo(ProfiloID, Name, Email, Gender, TipoAccesso, RisultatiRicerca, TemaUI, UltimoAccesso, CreatoIl) values ('" . $json_data_body->keyStore . "', '" . $json_data_body->name . "', '" . $json_data_body->email . "', '" . $json_data_body->gender . "', '" . $json_data_body->type . "', '" . $json_data_body->risRic . "', '" . $json_data_body->tema . "', NOW(), NOW())"; - - $retNewID = $mysqlconnetion->insertRecord($query); - $mysqlconnetion->disconnetti(); - - returnJson($app, $callbackFn, $retNewID); -}); - -$app->put('/profile', function () use ($app) { - $callbackFn = $app->request()->get('callback'); - $json_data_body = json_decode($app->request()->post('dataPair')); - $mysqlconnetion = new MysqlClass; - $query = "update profilo set RisultatiRicerca = '" . $json_data_body->risRic . "', TemaUI = '" . $json_data_body->tema . "' where ProfiloID = '" . $json_data_body->keyStore . "'"; - - $retNewID = $mysqlconnetion->insertRecord($query); - $mysqlconnetion->disconnetti(); - - returnJson($app, $callbackFn, $retNewID); -}); - -?> +get('/profile/:keyStore/ricetta/:ricetta_id', function ($keyStore, $ricetta_id) use ($app) { + $callbackFn = $app->request()->get('callback'); + $mysqlconnetion = new MysqlClass; + $query = "select COUNT(*) as Exist FROM blocco_note where ricetta_id = " . $ricetta_id . " AND ProfiloID = '" . $keyStore . "'"; + $retObj = $mysqlconnetion->queryToObject($query); + $mysqlconnetion->disconnetti(); + + returnJson($app, $callbackFn, $retObj[0]["Exist"]); +}); + +$app->post('/profile/ricetta', function () use ($app) { + $callbackFn = $app->request()->get('callback'); + $json_data_body = json_decode($app->request()->post('dataPair')); + $mysqlconnetion = new MysqlClass; + $query = "insert into blocco_note(ricetta_id, ProfiloID) values (" . $json_data_body->ricetta_id . ", '" . $json_data_body->keyStore . "')"; + $retNewID = $mysqlconnetion->insertRecord($query); + $mysqlconnetion->disconnetti(); + + returnJson($app, $callbackFn, $retNewID); +}); + +$app->delete('/profile/:keyStore/ricetta/:ricetta_id', function ($keyStore, $ricetta_id) use ($app) { + //$callbackFn = $app->request()->params('callback'); + $mysqlconnetion = new MysqlClass; + $query = "delete from blocco_note where ricetta_id = " . $ricetta_id . " AND ProfiloID = '" . $keyStore . "'"; + + $retNewID = $mysqlconnetion->insertRecord($query); + $mysqlconnetion->disconnetti(); + + echo $retNewID; + //returnJson($app, $callbackFn, $retNewID); +}); + +$app->delete('/profile/:keyStore/ricette', function ($keyStore) use ($app) { + $callbackFn = $app->request()->get('callback'); + $mysqlconnetion = new MysqlClass; + $query = "delete from blocco_note where ProfiloID = '" . $keyStore . "'"; + + $retNewID = $mysqlconnetion->insertRecord($query); + $mysqlconnetion->disconnetti(); + + returnJson($app, $callbackFn, $retNewID); +}); + +$app->get('/profile/:keyStore/ricette', function ($keyStore) use ($app) { + $callbackFn = $app->request()->get('callback'); + $mysqlconnetion = new MysqlClass; + $query = "select ID as ricetta_id, titolo, autore, valutazione, difficolta from ricette" . + " INNER JOIN blocco_note ON blocco_note.ricetta_id = ricette.id" . + " where blocco_note.ProfiloID = '" . $keyStore . "' order by titolo, autore"; + $retObj = $mysqlconnetion->queryToObject($query); + $mysqlconnetion->disconnetti(); + + foreach ($retObj as $ele) { + $ele["titolo"] = html_entity_decode($ele["titolo"]); + } + + returnJson($app, $callbackFn, $retObj); +}); + +$app->get('/profile/:keyStore', function ($keyStore) use ($app) { + $callbackFn = $app->request()->get('callback'); + $mysqlconnetion = new MysqlClass; + $query = "select ProfiloID, TipoAccesso, RisultatiRicerca, TemaUI, Name, Gender, 0 as NumRicette from profilo" . + " where ProfiloID = '" . $keyStore . "'"; + $retObj = $mysqlconnetion->queryToObject($query); + + $query = "update profilo set PenultimoAccesso = UltimoAccesso, UltimoAccesso = NOW() where ProfiloID = '" . $keyStore . "'"; + $mysqlconnetion->insertRecord($query); + + $query = "SELECT COUNT( * ) as NumRicette FROM ricette WHERE data_creazione > ( SELECT PenultimoAccesso FROM profilo " . + "WHERE `ProfiloID` = '" . $keyStore . "' )"; + + $retObj2 = $mysqlconnetion->queryToObject($query); + + $retObj[0]["NumRicette"] = $retObj2[0]["NumRicette"]; + + returnJson($app, $callbackFn, $retObj); +}); + +$app->post('/profile', function () use ($app) { + $callbackFn = $app->request()->get('callback'); + $json_data_body = json_decode($app->request()->post('dataPair')); + $mysqlconnetion = new MysqlClass; + $query = "insert into profilo(ProfiloID, Name, Email, Gender, TipoAccesso, RisultatiRicerca, TemaUI, UltimoAccesso, CreatoIl) values ('" . $json_data_body->keyStore . "', '" . $json_data_body->name . "', '" . $json_data_body->email . "', '" . $json_data_body->gender . "', '" . $json_data_body->type . "', '" . $json_data_body->risRic . "', '" . $json_data_body->tema . "', NOW(), NOW())"; + + $retNewID = $mysqlconnetion->insertRecord($query); + $mysqlconnetion->disconnetti(); + + returnJson($app, $callbackFn, $retNewID); +}); + +$app->put('/profile', function () use ($app) { + $callbackFn = $app->request()->get('callback'); + $json_data_body = json_decode($app->request()->post('dataPair')); + $mysqlconnetion = new MysqlClass; + $query = "update profilo set RisultatiRicerca = '" . $json_data_body->risRic . "', TemaUI = '" . $json_data_body->tema . "' where ProfiloID = '" . $json_data_body->keyStore . "'"; + + $retNewID = $mysqlconnetion->insertRecord($query); + $mysqlconnetion->disconnetti(); + + returnJson($app, $callbackFn, $retNewID); +}); + +?> diff --git a/ricette.php b/ricette.php index cd3d887..3d84941 100644 --- a/ricette.php +++ b/ricette.php @@ -33,7 +33,7 @@ $app->get('/typeqtys', function () use ($app) { returnJson($app, $callbackFn, $retObj); }); -$app->get('/categoryitems/:catID', function ($categoryID) use ($app) { +$app->get('/ricette/:catID', function ($categoryID) use ($app) { $callbackFn = $app->request()->get('callback'); $mysqlconnetion = new MysqlClass; //$mysqlconnetion->connetti(); @@ -48,7 +48,7 @@ $app->get('/categoryitems/:catID', function ($categoryID) use ($app) { returnJson($app, $callbackFn, $retObj); }); -$app->get('/categoryitems/:categoryID/mostvote(/:numItems)', function ($categoryID, $numItems = 10) use ($app) { +$app->get('/ricette/:categoryID/mostvote(/:numItems)', function ($categoryID, $numItems = 10) use ($app) { $callbackFn = $app->request()->get('callback'); $mysqlconnetion = new MysqlClass; //$mysqlconnetion->connetti(); @@ -63,7 +63,7 @@ $app->get('/categoryitems/:categoryID/mostvote(/:numItems)', function ($category returnJson($app, $callbackFn, $retObj); }); -$app->get('/categoryitems/:categoryID/lastinserted(/:numItems)', function ($categoryID, $numItems = 10) use ($app) { +$app->get('/ricette/:categoryID/lastinserted(/:numItems)', function ($categoryID, $numItems = 10) use ($app) { $callbackFn = $app->request()->get('callback'); $mysqlconnetion = new MysqlClass; //$mysqlconnetion->connetti(); @@ -78,7 +78,23 @@ $app->get('/categoryitems/:categoryID/lastinserted(/:numItems)', function ($cate returnJson($app, $callbackFn, $retObj); }); -$app->get('/categoryitems/search/:numItems(/:categoryId(/:difficolta(/:titolo)))', +$app->get('/ricette/lastinserted/:profileID', function ($profileID) use ($app) { + $callbackFn = $app->request()->get('callback'); + $mysqlconnetion = new MysqlClass; + //$mysqlconnetion->connetti(); + $query = "select ID as ricetta_id, titolo, autore FROM ricette WHERE data_creazione > ( SELECT PenultimoAccesso FROM profilo " . + "WHERE `ProfiloID` = '" . $profileID . "' ) order by Data_creazione desc, titolo, autore"; + $retObj = $mysqlconnetion->queryToObject($query); + $mysqlconnetion->disconnetti(); + + foreach ($retObj as $ele) { + $ele["titolo"] = html_entity_decode($ele["titolo"], ENT_COMPAT | ENT_HTML401, 'ISO-8859-1'); + } + + returnJson($app, $callbackFn, $retObj); +}); + +$app->get('/ricette/search/:numItems(/:categoryId(/:difficolta(/:titolo)))', function ($numItems = 10, $categoryId = 0, $difficolta = 0, $titolo = "") use ($app) { $callbackFn = $app->request()->get('callback'); //$filterItem = json_decode($app->request()->post('post')); diff --git a/serviceapp.php b/serviceapp.php index 0857f4b..648eabb 100644 --- a/serviceapp.php +++ b/serviceapp.php @@ -1,16 +1,16 @@ -group('/api', function () use ($app) { - include "./ricette.php"; - include "./profile.php"; - include "./image.php"; -}); - -$app->group('/backend', function () use ($app) { - include "./management.php"; -}); -//include "./image.php"; - +group('/api', function () use ($app, $dirRicetteDropBox) { + include "./ricette.php"; + include "./profile.php"; + include "./image.php"; +}); + +$app->group('/backend', function () use ($app) { + include "./management.php"; +}); +//include "./image.php"; + $app->run(); \ No newline at end of file diff --git a/utility.php b/utility.php index 76caec5..dc959cd 100644 --- a/utility.php +++ b/utility.php @@ -1,78 +1,87 @@ -= '300000') { - return false; - } - - /* step through inArray */ - foreach ($inArray as $key => $val) { - if (is_array($val)) { - /* recurse on array elements */ - $newArray[$key] = utf8json($val); - } else { - /* encode string values */ - $newArray[$key] = utf8_encode($val); - } - } - /* return utf8 encoded array */ - return $newArray; - } - /* return utf8 encoded array */ - return $inArray; -} - -function returnJsonWithDecode($app, $callbackFn, $retObj) { - if ($callbackFn) { - $app->contentType('application/javascript; Charset=UTF-8'); - echo $callbackFn . "(" . html_entity_decode(json_encode(utf8json($retObj)), ENT_COMPAT | ENT_HTML401, 'ISO-8859-1') . ")"; - } else { - $app->contentType('application/x-json; Charset=UTF-8'); - echo html_entity_decode(json_encode(utf8json($retObj)), ENT_COMPAT | ENT_HTML401, 'ISO-8859-1'); - } -} - -function returnJson($app, $callbackFn, $retObj) { - if ($callbackFn) { - $app->contentType('application/javascript; Charset=UTF-8'); - echo $callbackFn . "(" . (json_encode(utf8json($retObj))) . ")"; - } else { - $app->contentType('application/x-json; Charset=UTF-8'); - echo (json_encode(utf8json($retObj))); - } -} - -function makeThumbnail($im) { - $final_width_of_image = 300; - $ox = imagesx($im); - $oy = imagesy($im); - - $nx = $final_width_of_image; - $ny = floor($oy * ($final_width_of_image / $ox)); - - $nm = imagecreatetruecolor($nx, $ny); - - imagecopyresized($nm, $im, 0, 0, 0, 0, $nx, $ny, $ox, $oy); - - return $nm; -} - -function getContentFromResources($res) { - ob_start(); //Start output buffer. - imagejpeg($res); //This will normally output the image, but because of ob_start(), it won't. - $contents = ob_get_contents(); //Instead, output above is saved to $contents - ob_end_clean(); //End the output buffer. - - return $contents; -} - -?> += '300000') { + return false; + } + + /* step through inArray */ + foreach ($inArray as $key => $val) { + if (is_array($val)) { + /* recurse on array elements */ + $newArray[$key] = utf8json($val); + } else { + /* encode string values */ + $newArray[$key] = utf8_encode($val); + } + } + /* return utf8 encoded array */ + return $newArray; + } + /* return utf8 encoded array */ + return $inArray; +} + +function returnJsonWithDecode($app, $callbackFn, $retObj) { + if ($callbackFn) { + $app->contentType('application/javascript; Charset=UTF-8'); + echo $callbackFn . "(" . html_entity_decode(json_encode(utf8json($retObj)), ENT_COMPAT | ENT_HTML401, 'ISO-8859-1') . ")"; + } else { + $app->contentType('application/x-json; Charset=UTF-8'); + echo html_entity_decode(json_encode(utf8json($retObj)), ENT_COMPAT | ENT_HTML401, 'ISO-8859-1'); + } +} + +function returnJson($app, $callbackFn, $retObj) { + if ($callbackFn) { + $app->contentType('application/javascript; Charset=UTF-8'); + echo $callbackFn . "(" . (json_encode(utf8json($retObj))) . ")"; + } else { + $app->contentType('application/x-json; Charset=UTF-8'); + echo (json_encode(utf8json($retObj))); + } +} + +function makeThumbnail($im) { + $final_width_of_image = 300; + $ox = imagesx($im); + $oy = imagesy($im); + + $nx = $final_width_of_image; + $ny = floor($oy * ($final_width_of_image / $ox)); + + $nm = imagecreatetruecolor($nx, $ny); + + imagecopyresized($nm, $im, 0, 0, 0, 0, $nx, $ny, $ox, $oy); + + return $nm; +} + +function getContentFromResources($res) { + ob_start(); //Start output buffer. + imagejpeg($res); //This will normally output the image, but because of ob_start(), it won't. + $contents = ob_get_contents(); //Instead, output above is saved to $contents + ob_end_clean(); //End the output buffer. + + return $contents; +} + +?>