<?php /** * Cheryl 3.0 * * 2003 - 2013 Devin Smith * https://github.com/arzynik/cheryl * * Cheryl is a web based file manager for the modern web. Built * on top of PHP5 and AngularJS with lots of love from HTML5 and * CSS3 animations. * * In intall, just copy this script to where you want to share files. * See the config below for options. * */ ignore_user_abort(false); set_time_limit(10); date_default_timezone_set('Europe/Paris'); ini_set('zlib.output_compression','On'); ini_set('zlib.output_compression_level', 9); if (!defined('CHERYL_SALT')) { // password salt. make something random define('CHERYL_SALT', 'SALTTOCHANGE'); } class Cheryl { private static $_cheryl; private $defaultConfig = array( // the admin username nad password to access all features. if set to blank, all users will have access to all enabled features // array of users. this can be overwridden by custom user clases 'users' => array( array( 'username' => 'admin', 'password' => '', 'permissions' => 'all' // if set to all, all permissions are enabled. even new features addedd in the future ) ), 'authentication' => array( 'type' => 'simple' // simple: users are stored in the users array. mysql: uses a mysqli interface. pdo: uses pdo interface. see examples ), 'useSha1' => true, // if true, passwords will be hashed client side for security. 'root' => 'files', // the folder you want users to browse 'includes' => 'Cheryl', // path to look for additional libraries. leave blank if you dont know 'templateName' => 'cheryl', // name of the template to look for. leave alone if you dont know 'readonly' => false, // if true, disables all write features, and doesnt require authentication 'features' => array( 'snooping' => false, // if true, a user can browse filters behind the root directory, posibly exposing secure files. not reccomended 'recursiveBrowsing' => true, // if true, allows a simplified view that shows all files recursivly in a directory. with lots of files this can slow it down ), // files to hide from view 'hiddenFiles' => array( '.DS_Store', 'desktop.ini', '.git', '.svn', '.hg', '.trash', '.thumb', '.cherylconfig' ), 'trash' => true, // if true, deleting files will send to trash first 'libraries' => array( 'type' => 'remote' ), 'recursiveDelete' => true // if true, will allow deleting of unempty folders ); public $features = array( 'rewrite' => false, 'userewrite' => null, 'json' => false, 'gd' => false, 'exif' => false, 'imlib' => false, 'imcli' => false ); public $authed = false; public static function init($config = null) { if (!self::$_cheryl) { new Cheryl($config); } return self::$_cheryl; } public function __construct($config = null) { if (!self::$_cheryl) { self::$_cheryl = $this; } if (is_object($config)) { $config = (array)$config; } elseif(is_array($config)) { $config = $config; } else { $config = array(); } $config = array_merge($this->defaultConfig, $config); $config = Cheryl_Model::toModel($config); $this->config = $config; $this->_setup(); $this->_digestRequest(); $this->_authenticate(); } public static function script() { return preg_replace('@'.DIRECTORY_SEPARATOR.'((index|default)\.(php|htm|html))$@','',$_SERVER['SCRIPT_NAME']); } public static function password($password) { // just a pinch return sha1($password.CHERYL_SALT); } public static function me() { return self::$_cheryl; } public static function go() { self::me()->_request(); echo self::template(); } public static function template() { return Cheryl_Template::show(); } private function _request() { // process authentication requests switch ($this->requestPath[0]) { case 'logout': $this->_logout(); echo json_encode(array('status' => true, 'message' => 'logged out')); exit; case 'login': $res = $this->_login(); if ($res) { echo json_encode(array('status' => true, 'message' => 'logged in')); } else { echo json_encode(array('status' => false, 'message' => 'failed to log in')); } exit; // get the config and authentication status case 'config': $this->_getConfig(); exit; break; // list the contents of a directory case 'ls': $this->_requestList(); exit; break; // download a file case 'dl': $this->_getFile(true); exit; break; // upload a file case 'ul': $this->_takeFile(); exit; break; // view a file case 'vw': $this->_getFile(false); exit; break; // delete a file case 'rm': $this->_deleteFile(); exit; break; // rename a file case 'rn': $this->_renameFile(); exit; break; // make a directory case 'mk': $this->_makeFile(); exit; break; // save a file case 'sv': $this->_saveFile(); exit; break; // display icon case 'icon': header('Content-Type: image/png'); echo base64_decode('iVBORw0KGgoAAAANSUhEUgAAAJgAAACYCAYAAAAYwiAhAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3NpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDphYWFjYWRhNi1lYjI0LTQ2NTMtYWNmYi1jYzY2NDZhNDk0MzMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDYyNUIwMDQ1NkY4MTFFM0FFODVCQ0FBODlEMUY3OTkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDYyNUIwMDM1NkY4MTFFM0FFODVCQ0FBODlEMUY3OTkiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6YWFhY2FkYTYtZWIyNC00NjUzLWFjZmItY2M2NjQ2YTQ5NDMzIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOmFhYWNhZGE2LWViMjQtNDY1My1hY2ZiLWNjNjY0NmE0OTQzMyIvPiA8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'); exit; break; default: // display the main html document by letting it pass through php break; } } private function _setup() { $this->features = (object)$this->features; if (file_exists($this->config->includes)) { // use include root at script level $this->config->includes = realpath($this->config->includes).DIRECTORY_SEPARATOR; } elseif (file_exists(dirname(__FILE__).DIRECTORY_SEPARATOR.$this->config->includes)) { // use include root at lib level $this->config->includes = dirname(__FILE__).DIRECTORY_SEPARATOR.$this->config->includes.DIRECTORY_SEPARATOR; } else { // use current path $this->config->includes = realpath(__FILE__).DIRECTORY_SEPARATOR; } if (!$this->config->root) { $this->config->root = dirname($_SERVER['SCRIPT_FILENAME']).DIRECTORY_SEPARATOR; } else { $this->config->root = dirname($_SERVER['SCRIPT_FILENAME']).DIRECTORY_SEPARATOR.$this->config->root.DIRECTORY_SEPARATOR; if (!file_exists($this->config->root)) { @mkdir($this->config->root); @chmod($this->config->root, 0777); } } if ((function_exists('apache_get_modules') && in_array('mod_rewrite', apache_get_modules())) || getenv('HTTP_MOD_REWRITE') == 'On') { $this->features->rewrite = true; } if (!function_exists('json_decode')) { if (file_exists($this->config->includes.'Cheryl/Library/JSON.php')) { require_once($this->config->includes.'Cheryl/Library/JSON.php'); } } if (function_exists('json_decode')) { $this->features->json = true; } if (function_exists('exif_read_data')) { $this->features->exif = true; } if (function_exists('getimagesize')) { $this->features->gd = true; } if (function_exists('Imagick::identifyImage')) { $this->features->imlib = true; } if (!$this->features->imlib) { $o = shell_exec('identify -version 2>&1'); if (!strpos($o, 'not found')) { $this->features->imcli = 'identify'; } elseif (file_exists('/usr/local/bin/identify')) { $this->features->imcli = '/usr/local/bin/identify'; } elseif(file_exists('/usr/bin/identify')) { $this->features->imcli = '/usr/bin/identify'; } elseif(file_exists('/opt/local/bin/identify')) { $this->features->imcli = '/opt/local/bin/identify'; } elseif(file_exists('/bin/identify')) { $this->features->imcli = '/bin/identify'; } elseif(file_exists('/usr/bin/identify')) { $this->features->imcli = '/usr/bin/identify'; } } $stat = intval(trim(shell_exec('stat -f %B '.escapeshellarg(__FILE__)))); if ($stat && intval(filemtime(__FILE__)) != $stat) { $this->features->ctime = true; } } private function _authenticate() { // Patch: Authenticate automaticaly $this->user = new Cheryl_User('admin'); return $this->authed = true; if (!Cheryl_User::users()) { // allow anonymouse access. ur crazy! return $this->authed = true; } session_start(); if ($_SESSION['cheryl-authed']) { $this->user = new Cheryl_User($_SESSION['cheryl-username']); return $this->authed = true; } } private function _login() { $user = Cheryl_User::login(); if ($user) { $this->user = $user; $this->authed = $_SESSION['cheryl-authed'] = true; $_SESSION['cheryl-username'] = $this->user->username; return true; } else { return false; } } private function _logout() { @session_destroy(); @session_regenerate_id(); @session_start(); } private function _digestRequest() { if (strtolower($_SERVER['REQUEST_METHOD']) == 'post' && !$_REQUEST['__p']) { if (!$this->features->json) { header('Status: 400 Bad Request'); header('HTTP/1.0 400 Bad Request'); echo json_encode(array('status' => false, 'JSON is not installed on this server. requests must use query strings')); } else { $this->request = json_decode(file_get_contents('php://input'),true); } } else { $this->request = $_REQUEST; } if ($this->request['__p']) { // we have a page param result $url = explode('/',$this->request['__p']); $this->features->userewrite = false; } else { $url = false; } $this->requestPath = $url; // sanatize file/directory requests if ($this->request['_d']) { $this->request['_d'] = str_replace('/',DIRECTORY_SEPARATOR, $this->request['_d']); if ($this->config->features->snooping) { // just allow them to enter any old damn thing $this->requestDir = $this->config->root.$this->request['_d']; } else { $this->requestDir = preg_replace('/\.\.\/|\.\//i','',$this->request['_d']); //$this->requestDir = preg_replace('@^'.DIRECTORY_SEPARATOR.basename(__FILE__).'@','',$this->requestDir); $this->requestDir = $this->config->root.$this->requestDir; } if (file_exists($this->requestDir)) { $this->requestDir = dirname($this->requestDir).DIRECTORY_SEPARATOR.basename($this->requestDir); } else { $this->requestDir = null; } } // sanatize filename if ($this->request['_n']) { $this->requestName = preg_replace('@'.DIRECTORY_SEPARATOR.'@','',$this->request['_n']); } } private function _getFiles($dir, $filters = array()) { if ($filters['recursive']) { $iter = new RecursiveDirectoryIterator($dir); $iterator = new RecursiveIteratorIterator( $iter, RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD ); $filtered = new CherylFilterIterator($iterator); $paths = array($dir); foreach ($filtered as $path => $file) { if ($file->getFilename() == '.' || $file->getFilename() == '..') { continue; } if ($file->isDir()) { $dirs[] = $this->_getFileInfo($file); } elseif (!$file->isDir()) { $files[] = $this->_getFileInfo($file); } } } else { $iter = new CherylDirectoryIterator($dir); $filter = new CherylFilterIterator($iter); $iterator = new IteratorIterator($filter); $paths = array($dir); foreach ($iterator as $path => $file) { if ($file->isDot()) { continue; } if ($file->isDir()) { $dirs[] = $this->_getFileInfo($file); } elseif (!$file->isDir()) { $files[] = $this->_getFileInfo($file); } } } return array('dirs' => $dirs, 'files' => $files); } private function _cTime($file) { return trim(shell_exec('stat -f %B '.escapeshellarg($file->getPathname()))); } // do our own type detection private function _type($file, $extended = false) { $mime = mime_content_type($file->getPathname()); $mimes = explode('/',$mime); $type = strtolower($mimes[0]); $ext = $file->getExtension(); if ($ext == 'pdf') { $type = 'image'; } $ret = array( 'type' => $type, 'mime' => $mime ); if (!$extended) { return $ret['type']; } else { return $ret; } } private function _getFileInfo($file, $extended = false) { $path = str_replace(realpath($this->config->root),'',realpath($file->getPath())); if ($file->isDir()) { $info = array( 'path' => $path, 'name' => $file->getFilename(), 'writeable' => $file->isWritable(), 'type' => $this->_type($file, false) ); } elseif (!$file->isDir()) { $info = array( 'path' => $path, 'name' => $file->getFilename(), 'size' => $file->getSize(), 'mtime' => $file->getMTime(), 'ext' => $file->getExtension(), 'writeable' => $file->isWritable() ); if ($this->features->ctime) { $info['ctime'] = $this->_cTime($file); } if ($extended) { $type = $this->_type($file, true); $info['type'] = $type['type']; $info['meta'] = array( 'mime' => $type['mime'] ); if ($type['type'] == 'text') { $info['contents'] = file_get_contents($file->getPathname()); } if (strpos($mime, 'image') > -1) { if ($this->features->exif) { $exif = @exif_read_data($file->getPathname()); if ($exif) { $keys = array('Make','Model','ExposureTime','FNumber','ISOSpeedRatings','FocalLength','Flash'); foreach ($keys as $key) { if (!$exif[$key]) { continue; } $exifInfo[$key] = $exif[$key]; } if ($exif['DateTime']) { $d = new DateTime($exif['DateTime']); $exifInfo['Created'] = $d->getTimestamp(); } elseif ($exif['FileDateTime']) { $exifInfo['Created'] = $exif['FileDateTime']; } if ($exif['COMPUTED']['CCDWidth']) { $exifInfo['CCDWidth'] = $exif['COMPUTED']['CCDWidth']; } if ($exif['COMPUTED']['ApertureFNumber']) { $exifInfo['ApertureFNumber'] = $exif['COMPUTED']['ApertureFNumber']; } if ($exif['COMPUTED']['Height']) { $height = $exif['COMPUTED']['Height']; } if ($exif['COMPUTED']['Width']) { $width = $exif['COMPUTED']['Width']; } } } $info['meta']['exif'] = $exifInfo; } if (!$height || !$width) { if ($this->features->gd) { $is = @getimagesize($file->getPathname()); if ($is[0]) { $width = $is[0]; $height = $is[1]; } } } if ($height && $width) { $info['meta']['height'] = $height; $info['meta']['width'] = $width; } } $info['meta']['mime'] = $mime; $info['perms'] = $file->getPerms(); } return $info; } private function _getFile($download = false) { if (!$this->authed && !$this->config->readonly) { echo json_encode(array('status' => false, 'message' => 'not authenticated')); exit; } if (!$this->requestDir || !is_file($this->requestDir)) { header('Status: 404 Not Found'); header('HTTP/1.0 404 Not Found'); exit; } $file = new SplFileObject($this->requestDir); // not really sure if this range shit works. stole it from an old script i wrote if (isset($_SERVER['HTTP_RANGE'])) { list($size_unit, $range_orig) = explode('=', $_SERVER['HTTP_RANGE'], 2); if ($size_unit == 'bytes') { list($range, $extra_ranges) = explode(',', $range_orig, 2); } else { $range = ''; } if ($range) { list ($seek_start, $seek_end) = explode('-', $range, 2); } $seek_end = (empty($seek_end)) ? ($size - 1) : min(abs(intval($seek_end)),($size - 1)); $seek_start = (empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs(intval($seek_start)),0); if ($seek_start > 0 || $seek_end < ($size - 1)) { header('HTTP/1.1 206 Partial Content'); } else { header('HTTP/1.1 200 OK'); } header('Accept-Ranges: bytes'); header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$size); $contentLength = ($seek_end - $seek_start + 1); } else { header('HTTP/1.1 200 OK'); header('Accept-Ranges: bytes'); $contentLength = $file->getSize(); } header('Pragma: public'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Date: '.date('r')); header('Last-Modified: '.date('r',$file->getMTime())); header('Content-Length: '.$contentLength); header('Content-Transfer-Encoding: binary'); if ($download) { header('Content-Disposition: attachment; filename="'.$file->getFilename().'"'); header('Content-Type: application/force-download'); } else { header('Content-Type: '. mime_content_type($file->getPathname())); } // i wrote this freading a really long time ago but it seems to be more robust than SPL. someone correct me if im wrong $fp = fopen($file->getPathname(), 'rb'); fseek($fp, $seek_start); while(!feof($fp)) { set_time_limit(0); print(fread($fp, 1024*8)); flush(); ob_flush(); } fclose($fp); exit; } private function _requestList() { if (!$this->authed && !$this->config->readonly) { echo json_encode(array('status' => false, 'message' => 'not authenticated')); exit; } if (!$this->requestDir) { header('Status: 404 Not Found'); header('HTTP/1.0 404 Not Found'); exit; } if (is_file($this->requestDir)) { $file = new SplFileObject($this->requestDir); $info = $this->_getFileInfo($file, true); echo json_encode(array('type' => 'file', 'file' => $info)); } else { if (realpath($this->requestDir) == realpath($this->config->root)) { $path = ''; $name = ''; } else { $dir = pathinfo($this->requestDir); $path = str_replace(realpath($this->config->root),'',realpath($dir['dirname'])); $name = basename($this->requestDir); $path = $path{0} == '/' ? $path : '/'.$path; } $info = array( 'path' => $path, 'writeable' => is_writable($this->requestDir), 'name' => $name ); $files = $this->_getFiles($this->requestDir, array( 'recursive' => $this->request['filters']['recursive'] )); echo json_encode(array('type' => 'dir', 'list' => $files, 'file' => $info)); } } private function _takeFile() { if (!$this->authed) { echo json_encode(array('status' => false, 'message' => 'not authenticated')); exit; } if ($this->config->readonly || !$this->user->permission('upload', $this->requestDir)) { echo json_encode(array('status' => false, 'message' => 'no permission')); exit; } foreach ($_FILES as $file) { move_uploaded_file($file['tmp_name'],$this->requestDir.DIRECTORY_SEPARATOR.$file['name']); } echo json_encode(array('status' => true)); } private function _deleteFile() { if (!$this->authed) { echo json_encode(array('status' => false, 'message' => 'not authenticated')); exit; } if ($this->config->readonly || !$this->user->permission('delete', $this->requestDir)) { echo json_encode(array('status' => false, 'message' => 'no permission')); exit; } $status = false; if (is_dir($this->requestDir)) { if ($this->config->recursiveDelete) { foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->requestDir), RecursiveIteratorIterator::CHILD_FIRST) as $path) { if ($path->getFilename() == '.' || $path->getFilename() == '..') { continue; } $path->isFile() ? unlink($path->getPathname()) : rmdir($path->getPathname()); } } if (rmdir($this->requestDir)) { $status = true; } } else { if (unlink($this->requestDir)) { $status = true; } } echo json_encode(array('status' => $status)); } private function _renameFile() { if (!$this->authed) { echo json_encode(array('status' => false, 'message' => 'not authenticated')); exit; } if ($this->config->readonly || !$this->user->permission('rename', $this->requestDir)) { echo json_encode(array('status' => false, 'message' => 'no permission')); exit; } if (@rename($this->requestDir, dirname($this->requestDir).DIRECTORY_SEPARATOR.$this->requestName)) { $status = true; } else { $status = false; } echo json_encode(array('status' => $status, 'name' => $this->requestName)); } private function _makeFile() { if (!$this->authed) { echo json_encode(array('status' => false, 'message' => 'not authenticated')); exit; } if ($this->config->readonly || !$this->user->permission('create', $this->requestDir)) { echo json_encode(array('status' => false, 'message' => 'no permission')); exit; } if (@mkdir($this->requestDir.DIRECTORY_SEPARATOR.$this->requestName,0777)) { $status = true; } else { $status = false; } echo json_encode(array('status' => $status, 'name' => $this->requestName)); } private function _saveFile() { if (!$this->authed) { echo json_encode(array('status' => false, 'message' => 'not authenticated')); exit; } if ($this->config->readonly || !$this->user->permission('save', $this->requestDir)) { echo json_encode(array('status' => false, 'message' => 'no permission')); exit; } if (@file_put_contents($this->requestDir,$this->request['c'])) { $status = true; } else { $status = false; } echo json_encode(array('status' => $status)); } private function _getConfig() { echo json_encode(array('status' => true, 'authed' => $this->authed)); } public static function iteratorFilter($current) { return !in_array( $current->getFileName(), self::me()->config->hiddenFiles, true ); } } class CherylFilterIterator extends FilterIterator { public function accept() { return Cheryl::iteratorFilter($this->current()); } } class CherylDirectoryIterator extends DirectoryIterator { public function getExtension() { if (method_exists(get_parent_class($this), 'getExtension')) { $ext = parent::getExtension(); } else { $ext = pathinfo($this->getPathName(), PATHINFO_EXTENSION); } return strtolower($ext); } } class Cheryl_Model { public static function toModel($array) { $object = new Cheryl_Model(); if (is_array($array) && count($array) > 0) { foreach ($array as $name => $value) { if ($name === 0) { $isArray = true; } if (!empty($name) || $name === 0) { if (is_array($value)) { if (!count($value)) { $value = null; } else { $value = self::toModel($value); } } if ($isArray) { switch ($value) { case 'false': $array[$name] = false; break; case 'true': $array[$name] = true; break; case 'null': $array[$name] = null; break; default: $array[$name] = $value; break; } } else { $name = trim($name); switch ($value) { case 'false': $object->$name = false; break; case 'true': $object->$name = true; break; case 'null': $object->$name = null; break; default: $object->$name = $value; break; } } } } } return $isArray ? $array : $object; } } // we need to at least be able to encode data if (!function_exists('json_encode')) { function json_encode($data) { switch ($type = gettype($data)) { case 'NULL': return 'null'; case 'boolean': return ($data ? 'true' : 'false'); case 'integer': case 'double': case 'float': return $data; case 'string': return '"' . addslashes($data) . '"'; case 'object': $data = get_object_vars($data); case 'array': $output_index_count = 0; $output_indexed = array(); $output_associative = array(); foreach ($data as $key => $value) { $output_indexed[] = json_encode($value); $output_associative[] = json_encode($key) . ':' . json_encode($value); if ($output_index_count !== NULL && $output_index_count++ !== $key) { $output_index_count = NULL; } } if ($output_index_count !== NULL) { return '[' . implode(',', $output_indexed) . ']'; } else { return '{' . implode(',', $output_associative) . '}'; } default: return ''; } } } if (!class_exists('Cheryl_Template')) { class Cheryl_Template { public static function build($dir, $template, $show = false) { if ($show) { ob_start(); } $path = $dir.DIRECTORY_SEPARATOR.'Template'.DIRECTORY_SEPARATOR.$template; if (file_exists($path.'.phtml')) { // use the template $template = file_get_contents($path.'.phtml'); if (file_exists($path.'.css')) { $template = str_replace('<style></style>','<style>'.file_get_contents($path.'.css').'</style>', $template); } if (file_exists($path.'.js')) { $template = str_replace('<script></script>','<script>'.file_get_contents($path.'.js').'</script>', $template); } if ($show) { $temp = tempnam(null,'cheryl-template'); file_put_contents($temp, $template); include($temp); } else { $res = $template; } } if ($show) { $res = ob_get_contents(); ob_end_clean(); } return $res; } public static function show() { $res = self::build(Cheryl::me()->config->includes, Cheryl::me()->config->templateName, true); if (!$res) { ob_start(); ?> <!DOCTYPE HTML> <html ng-app="Cheryl"> <head> <title>Cheryl</title> <style>html, body, margin, form, a, h1, h2, h3, h4, h5, h6, select, input, tr, td, table, ul, ol, li, textarea, p, button { margin: 0; padding: 0; } body { background: #eceff1; color: #404040; background: #eceff1 -webkit-gradient(linear, left top, left bottom, color-stop(0%,#48aed9), color-stop(1000%,#48aed9)); background-size: 100% 142px; background-repeat:no-repeat; } body, input, button { font: 10px "Open Sans", "Helvetica", "Arial", sans-serif; } :focus { outline: none; } ::selection { background: rgba(255,39,151,.75); color: #fff; } ::-moz-selection { background: rgba(255,39,151,.75); color: #fff; } a, a:visited, a:active { text-decoration: none; color: #404040; } .wrapper { width: 870px; margin: 0 auto; margin-bottom: 25px; } .clearfix:after { content: ''; display: block; clear: both; visibility: hidden; line-height: 0; height: 0; } .logo svg { height: 90px; width: 90px; } .panel { float: left; width: 170px; margin: 0 20px 0 0; } .logo { margin: 30px 0 40px 40px; } .toggles { float: left; width: 680px; margin: 20px 0 0 0; } .content { float: left; width: 630px; min-height: 500px; background: #fff; box-shadow: 0px 1px 4px rgba(0,0,0,.3); padding: 25px; margin: 25px 0 20px 0; } h1 { color: #555963; font-weight: 100; font-size: 2em; } h2 { color: #404040; font-weight: 100; font-size: 1.5em; margin-bottom: .5em; } h1 input, h2 input { margin: 0; padding: 0; border: 1px dashed #f6f6f6; width: 20em; color: #555963; font-weight: 100; font-size: 1em; -webkit-transition: .2s border; } h2 input { border: 1px dashed #d0d0d0; padding: .3em; } .file-name-top, h1 input { padding-left: .2em; } h1 input:hover { border: 1px dashed #d0d0d0; } h1 input:focus, h2 input:focus { border: 1px dashed #b0b0b0; } .file-name-top { border: 1px solid transparent; } .toggles button { border: 0; background: rgba(0,0,0,.2); border-radius: 5px; color: #fff; font-size: 1.1em; padding: .5em 1.2em .6em 1.2em; cursor: pointer; opacity: .5; -webkit-transition: .2s opacity; width: 12em; } .toggles button.enabled { opacity: .8; } .toggles button:hover { opacity: .7; } .toggles button.enabled:hover { opacity: 1; } .toggles .search { border: 0; background: rgba(0,0,0,.2); border-radius: 5px; color: #fff; font-size: 1.1em; padding: .2em .4em .2em .8em; opacity: .5; -webkit-transition: .2s opacity; float: right; } .toggles .search .fa { vertical-align: middle; } .toggles .search .search-box { background: 0; padding: .35em .4em .45em .4em; border: 0; color: #fff; width: 8em; font-size: 1em; margin: 0; vertical-align: middle; -webkit-transition: .2s width; } .toggles .search.active { opacity: .8; } .toggles .search.active .search-box { width: 15em; } .toggles .search .search-box::-webkit-input-placeholder { color: #fff; -webkit-transition: .2s opacity; } .toggles .search .search-box::-moz-placeholder { color: #fff; -moz-transition: .2s opacity; } .toggles .search .search-box::-ms-input-placeholder { color: #fff; -ms-transition: .2s opacity; } .toggles .search .search-box::-o-input-placeholder { color: #fff; -o-transition: .2s opacity; } .toggles .search .search-box::input-placeholder { color: #fff; transition: .2s opacity; } .toggles .search.active .search-box::-webkit-input-placeholder { opacity: 0; } .toggles .search.active .search-box::-moz-placeholder { opacity: 0; } .toggles .search.active .search-box::-ms-placeholder { opacity: 0; } .toggles .search.active .search-box::-o-input-placeholder { opacity: 0; } .toggles .search.active .search-box::input-placeholder { opacity: 0; } .copyright { clear: both; float: right; cursor: pointer; } .copyright a { text-decoration: none; color: #cacccd; font-size: 2em; } .powered, .cheryl { -webkit-transition: .4s all; } .powered { opacity: .3; } .copyright:hover .powered { opacity: .7; } .copyright:hover .cheryl { color: #f83ca2; } .details .info { color: #767676; border-radius: 4px; padding: .2em 0 .2em 0; font-size: 1.2em; list-style: none; } .filter { background: #e0e2e4; color: #767676; display: block; border-radius: 4px; padding: .4em .8em .4em .8em; margin-bottom: .2em; font-size: 1.2em; cursor: pointer; } .filter.enabled { background: #a4d4e9; color: #fff; } .file .icon { font-size: 4em; color: #c0c0c0; width: 1em; height: 1em; display: inline-block; vertical-align: top; } .file .icon .fa { -webkit-transition: .2s all; position: absolute; display: block; } .file .icon .fa-cloud-upload { font-size: .85em; padding-top: .2em; } .file .icon .fa-download { opacity: 0; font-size: .9em; padding-top: .2em; } .file { background: #f0f0f0; padding: .8em 1.4em .8em 1.4em; cursor: pointer; -webkit-transition: .2s all; margin-bottom: .8em; display: block; border: 1px solid #f0f0f0; } .files .file:hover { background: #ecf3f9; } .files .file .icon:hover .fa-file-text-o { opacity: 0; } .files .file .icon:hover .fa-download { opacity: 1; } .files .file:focus { background: #ecf3f9; border: 1px solid #e0e6ec; } .files .file:hover .icon { color: #b5b5b5; } .uploads { margin-top: 1.4em; } .files { margin-top: 1.4em; } .file .attrs { display: inline-block; color: #9ea0a4; font-size: 1.1em; text-align: right; line-height: 1.7em; margin-top: .3em; float: right; } .file .filename { color: #303238; font-size: 17px; font-weight: 600; } .file .path { color: #9ea0a4; font-size: 1.1em; line-height: 1.6em; } .file .fileinfo { display: inline-block; margin-left: 1.5em; } .item-count { float: right; opacity: .7; } button, .filter { -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; -o-user-select: none; user-select: none; } .file-image { background-size: contain !important; background-repeat: no-repeat !important; width: 500px; height: 500px; } #downloader { display: none; } .upload { visibility: hidden; width: 0; height: 0; } .actions { float: right; text-align: right; margin-top: -4.3em; } .actions button { background: #555963; border: 1px solid #555963; border-radius: 4px; color: #fff; font-size: 1.4em; padding: .2em .4em .2em .4em; width: 2.7em; cursor: pointer; -webkit-transition: .15s all; margin-right: .3em; } .actions button:hover { background: #f0f0f0; color: #555963; border: 1px solid #9ea1a7; } .location .path { display: inline-block; margin-left: 4.1em; } @-webkit-keyframes progress-bar-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } } @-moz-keyframes progress-bar-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } } @-o-keyframes progress-bar-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } } @keyframes progress-bar-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } } .progress { height: 5.8em; overflow: hidden; background-color: #555963; float: left; width: 100%; } .progress-bar { overflow: hidden; height: 100%; width: 100%; background-color: #428bca; -webkit-transition: width 0.6s ease; -moz-transition: width 0.6s ease; -ms-transition: width 0.6s ease; -o-transition: width 0.6s ease; transition: width 0.6s ease; } .progress-striped .progress-bar { background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-size: 40px 40px; } .progress.active .progress-bar { -webkit-animation: progress-bar-stripes 2s linear infinite; -moz-animation: progress-bar-stripes 2s linear infinite; -ms-animation: progress-bar-stripes 2s linear infinite; -o-animation: progress-bar-stripes 2s linear infinite; animation: progress-bar-stripes 2s linear infinite; } .progress-bar-success { background-color: #5cb85c; } .progress-bar-info { background-color: #5bc0de; } .progress-bar-danger { background-color: #d9534f; } .upload-item { padding: 0; } .upload-content { padding: .8em 1.4em .8em 1.4em; float: left; margin-top: -5.8em; width: 95%; } .upload-content .filename, .upload-content .icon, .upload-content .attrs, .upload-content .path { color: #fff; } .modal-wrap { opacity: 0; pointer-events: none; -webkit-transition: .2s opacity; position: fixed; bottom: 0; height: 0; width: 0; z-index: 1000; } .modal-enabled { overflow: hidden; } .login-wrap, .modal-enabled .modal-wrap { position: fixed; width: 100%; height: 100%; top: 0; left: 0; right: 0; bottom: 0; overflow: hidden; } .login-wrap { background: #46aad5; } .modal-wrap { background: rgba(34,53,62,.7); } .modal-enabled .modal-wrap { opacity: 1; pointer-events: auto; } .login .welcome { color: #fff; font-size: 4.5em; font-weight: 100; text-align: center; margin-bottom: .8em; } .login .input-wrap { color: #fff; border-radius: 5px; background: rgba(0,0,0,.26); font-size: 2em; padding: .4em .6em .4em .6em; width: 100%; box-sizing: border-box; font-weight: 100; margin-bottom: .27em; } .login input { width: 100%; font-size: 1em; font-weight: 100; border: 0; background: none; color: #fff; } .login .field, .login .label { display: table-cell; } .login .field { width: 100%; } .login .label { min-width: 5.5em; opacity: .7; } .login { width: 35em; margin: 0 auto; margin-top: 10em; } .login-button { border-radius: 5px; background: rgba(0,0,0,.76); padding: .4em .6em .4em .6em; width: 100%; box-sizing: border-box; border: none; font-size: 2em; color: #fff; cursor: pointer; -webkit-transition: .2s all; } .copyright-login { opacity: .2; font-size: 2em; margin-top: 2em; text-align: right; -webkit-transition: .4s all; } .copyright-login:hover { opacity: .7; } .copyright-login:hover .cheryl { color: #f83ca2; } .filter-name { max-width: 2em; text-overflow:ellipsis; display: inline-block; overflow: hidden; max-width: 10em; height: 1.3em; vertical-align: top; } .modal { background: #fff; width: 36em; margin: 0 auto; margin-top: 20em; padding: 2em; min-height: 11em; text-align: center; box-shadow: 0px 0px 0px 4px rgba(0,0,0,.14); } .modal-dropupload { background: none; border-radius: 10px; border: 2px dashed #fff; box-shadow: none; width: 28em; color: #fff; } .modal-dropupload h1 { color: #fff; font-size: 9em; margin-top: .4em; line-height: 1em; } .modal-dropupload h2 { color: #fff; font-size: 2em; margin-bottom: 1.6em; } .modal button { border: none; padding: .45em 2em .45em 2em; font-size: 1.4em; margin: 0 .5em 0 .5em; cursor: pointer; border-radius: 3px; background: #f0f0f0; color: #555963; border: 1px solid #9ea1a7; -webkit-transition: .15s all; } .modal button:focus, .modal button:hover { background: #555963; color: #fff; border: 1px solid #555963; } @-webkit-keyframes shake { 0% { -webkit-transform: translate(2px, 1px) rotate(0deg); } 10% { -webkit-transform: translate(-1px, -2px) rotate(-1deg); } 20% { -webkit-transform: translate(-3px, 0px) rotate(1deg); } 30% { -webkit-transform: translate(0px, 2px) rotate(0deg); } 40% { -webkit-transform: translate(1px, -1px) rotate(1deg); } 50% { -webkit-transform: translate(-1px, 1px) rotate(-1deg); } 60% { -webkit-transform: translate(-3px, -2px) rotate(0deg); } 70% { -webkit-transform: translate(2px, 1px) rotate(-1deg); } 80% { -webkit-transform: translate(-1px, -2px) rotate(1deg); } 90% { -webkit-transform: translate(2px, -1px) rotate(0deg); } 100% { -webkit-transform: translate(1px, -2px) rotate(-1deg); } } .global-error .logo svg { -webkit-animation-name: 'shake'; -webkit-animation-duration: 0.3s; -webkit-transform-origin:50% 50%; -webkit-animation-iteration-count: 3; -webkit-animation-timing-function: linear; } #editor { height: 100%; min-height: 500px; font-size: 11px; } .file-contents { margin-top: 1em; } .fullscreen-editor #editor { height: auto !important; width: auto !important; border: 0; margin: 0; position: fixed !important; top: 0; bottom: 0; left: 0; right: 0; z-index: 10000 } .fullscreen-editor { overflow: hidden } .animated { -webkit-animation-fill-mode: both; -moz-animation-fill-mode: both; -ms-animation-fill-mode: both; -o-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation-duration: 1s; -moz-animation-duration: 1s; -ms-animation-duration: 1s; -o-animation-duration: 1s; animation-duration: 1s; } .welcome { -webkit-animation-delay: .4s; -moz-animation-delay: .4s; -ms-animation-delay: .4s; -o-animation-delay: .4s; animation-delay: .4s; } .login-form { -webkit-animation-delay: 1.1s; -moz-animation-delay: 1.1s; -ms-animation-delay: 1.1s; -o-animation-delay: 1.1s; animation-delay: 1.1s; } @-webkit-keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } @-moz-keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } @-ms-keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } @-o-keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } @keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } @-webkit-keyframes fadeInDown { 0% { opacity: 0; -webkit-transform: translateY(-20px); } 100% { opacity: 1; -webkit-transform: translateY(0); } } @-moz-keyframes fadeInDown { 0% { opacity: 0; -moz-transform: translateY(-20px); } 100% { opacity: 1; -moz-transform: translateY(0); } } @-ms-keyframes fadeInDown { 0% { opacity: 0; -ms-transform: translateY(-20px); } 100% { opacity: 1; -ms-transform: translateY(0); } } @-o-keyframes fadeInDown { 0% { opacity: 0; -o-transform: translateY(-20px); } 100% { opacity: 1; -o-transform: translateY(0); } } @keyframes fadeInDown { 0% { opacity: 0; transform: translateY(-20px); } 100% { opacity: 1; transform: translateY(0); } } .fadeInDown { -webkit-animation-name: fadeInDown; -moz-animation-name: fadeInDown; -ms-animation-name: fadeInDown; -o-animation-name: fadeInDown; animation-name: fadeInDown; } .fadeIn { -webkit-animation-name: fadeIn; -moz-animation-name: fadeIn; -ms-animation-name: fadeIn; -o-animation-name: fadeIn; animation-name: fadeIn; } </style> <link href="_assets/font-awesome/css/font-awesome.min.css" rel="stylesheet"> <link href="_assets/fonts.css" rel="stylesheet"> </head> <body ng-controller="RootCtrl" ng-class="{'modal-enabled': dialog, 'global-error': (dialog && dialog.type == 'error'), 'fullscreen-editor': fullscreenEdit}" ng-body ng-drop-upload> <div class="wrapper clearfix" ng-show="authed"> <div class="panel"> <a href="<?php echo Cheryl::script() ? Cheryl::script() : '/' ?>"><div class="logo"> <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="689.318px" height="642.217px" viewBox="0 0 689.318 642.217" enable-background="new 0 0 689.318 642.217" xml:space="preserve"> <g> <g> <g> <g> <ellipse transform="matrix(-0.6304 -0.7763 0.7763 -0.6304 829.5235 668.4048)" fill="#3B1410" cx="573.881" cy="136.727" rx="112.318" ry="117.438"/> <g> <g> <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-402.9502" y1="939.6608" x2="-331.6008" y2="939.6608" gradientTransform="matrix(-0.0414 -0.999 0.999 -0.0414 -313.7207 -151.8308)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_1_)" d="M610.424,213.071c0,0,63.683,1.451,59.549-73.829 C669.974,139.242,663.009,200.72,610.424,213.071z"/> <linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="335.5046" y1="363.5505" x2="410.826" y2="363.5505" gradientTransform="matrix(0.7423 0.67 0.67 -0.7423 67.1035 77.1552)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_2_)" d="M538.389,55.726c0,0,40.268-47.276,98.591,3.174C636.98,58.901,582.618,25.227,538.389,55.726z "/> <linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-2232.4961" y1="-587.3471" x2="-2176.293" y2="-587.3471" gradientTransform="matrix(-0.5277 0.8493 -0.8493 -0.5277 -1062.6609 1651.484)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_3_)" d="M645.642,86.604c0,0-56.077-31.247-93.199,6.516C552.443,93.12,587.056,35.894,645.642,86.604z "/> <linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="-2228.9397" y1="-295.3342" x2="-2155.5984" y2="-295.3342" gradientTransform="matrix(-0.6438 0.7652 -0.7652 -0.6438 -1035.2269 1601.1501)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_4_)" d="M645.847,102.606c0,0-50.104-21.263-87.027,22.627 C558.819,125.233,592.348,71.114,645.847,102.606z"/> <linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="-2289.9167" y1="-302.4471" x2="-2206.2373" y2="-302.4471" gradientTransform="matrix(-0.8224 0.569 -0.569 -0.8224 -1393.106 1197.1461)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_5_)" d="M657.495,136.096c0,0-17.959,53.366-70.557,45.1 C586.939,181.197,644.183,201.136,657.495,136.096z"/> <linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="-2219.0256" y1="-316.291" x2="-2147.5671" y2="-316.291" gradientTransform="matrix(-0.6438 0.7652 -0.7652 -0.6438 -1035.2269 1601.1501)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_6_)" d="M646.085,115.763c0,0-21.869,30.751-68.64,35.636 C577.445,151.399,620.6,161.903,646.085,115.763z"/> </g> </g> </g> <g> <path fill="#3B1410" d="M186.242,46.116c50.348,40.887,59.462,113.069,20.359,161.221 c-39.108,48.152-111.623,54.042-161.972,13.156c-50.345-40.89-59.462-113.072-20.355-161.226 C63.379,11.115,135.893,5.225,186.242,46.116z"/> <g> <g> <linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="-434.0402" y1="1772.5775" x2="-362.6902" y2="1772.5775" gradientTransform="matrix(0.0414 -0.999 -0.999 -0.0414 1836.4091 -151.8308)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_7_)" d="M78.892,209.647c0,0-63.684,1.452-59.548-73.83C19.345,135.817,26.309,197.297,78.892,209.647z "/> <linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="951.8776" y1="924.5019" x2="1027.199" y2="924.5019" gradientTransform="matrix(-0.7423 0.67 -0.67 -0.7423 1455.5847 77.1552)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_8_)" d="M150.929,52.302c0,0-40.269-47.275-98.591,3.174C52.337,55.476,106.7,21.805,150.929,52.302z" /> <linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="-2675.2734" y1="-1293.4803" x2="-2619.0691" y2="-1293.4803" gradientTransform="matrix(0.5277 0.8493 0.8493 -0.5277 2585.3501 1651.484)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_9_)" d="M43.675,83.179c0,0,56.078-31.247,93.198,6.518C136.873,89.697,102.262,32.471,43.675,83.179z" /> <linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="-2768.0786" y1="-930.8193" x2="-2694.7368" y2="-930.8193" gradientTransform="matrix(0.6438 0.7652 0.7652 -0.6438 2557.9155 1601.1501)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_10_)" d="M43.471,99.183c0,0,50.104-21.261,87.028,22.626C130.499,121.809,96.969,67.691,43.471,99.183 z"/> <linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="-2977.1575" y1="-773.7715" x2="-2893.4783" y2="-773.7715" gradientTransform="matrix(0.8224 0.569 0.569 -0.8224 2915.7942 1197.1461)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_11_)" d="M31.822,132.674c0,0,17.958,53.365,70.557,45.1 C102.379,177.774,45.134,197.711,31.822,132.674z"/> <linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="-2758.1646" y1="-951.7772" x2="-2686.707" y2="-951.7772" gradientTransform="matrix(0.6438 0.7652 0.7652 -0.6438 2557.9155 1601.1501)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_12_)" d="M43.232,112.34c0,0,21.869,30.75,68.64,35.635C111.872,147.975,68.717,158.48,43.232,112.34z" /> </g> </g> </g> <g> <linearGradient id="SVGID_13_" gradientUnits="userSpaceOnUse" x1="311.1925" y1="63.994" x2="360.3353" y2="424.3733"> <stop offset="0.0056" style="stop-color:#E3B087"/> <stop offset="0.0291" style="stop-color:#E5B38B"/> <stop offset="0.1391" style="stop-color:#ECC09A"/> <stop offset="0.2753" style="stop-color:#F1C9A5"/> <stop offset="0.4672" style="stop-color:#F4CEAB"/> <stop offset="1" style="stop-color:#F5D0AD"/> </linearGradient> <path fill="url(#SVGID_13_)" d="M349.073,57.331c-151.457,0-274.236,127.366-274.236,284.479 c0,22.437,2.513,44.266,7.247,65.204C110.5,532.7,220.382,642.217,350.21,642.217c127.014,0,232.705-105.509,263.884-227.083 c6.001-23.396,9.217-47.971,9.217-73.324C623.311,184.697,500.529,57.331,349.073,57.331z"/> <g> <radialGradient id="SVGID_14_" cx="214.0404" cy="537.9091" r="39.4764" gradientUnits="userSpaceOnUse"> <stop offset="0" style="stop-color:#F8AEAB"/> <stop offset="0.2779" style="stop-color:#F7B3AB"/> <stop offset="0.721" style="stop-color:#F5C4AD"/> <stop offset="1" style="stop-color:#F5D0AD"/> </radialGradient> <ellipse fill="url(#SVGID_14_)" cx="214.04" cy="537.907" rx="40.964" ry="37.933"/> <radialGradient id="SVGID_15_" cx="484.1053" cy="537.9091" r="39.4767" gradientUnits="userSpaceOnUse"> <stop offset="0" style="stop-color:#F8AEAB"/> <stop offset="0.2779" style="stop-color:#F7B3AB"/> <stop offset="0.721" style="stop-color:#F5C4AD"/> <stop offset="1" style="stop-color:#F5D0AD"/> </radialGradient> <ellipse fill="url(#SVGID_15_)" cx="484.105" cy="537.907" rx="40.964" ry="37.933"/> </g> <g> <g> <g> <path fill="#3B1410" d="M492.486,387.328c-10.565-0.004-21.142,5.141-28.662,15.414l0,0v-0.003 c-0.359,0.493-0.309,1.233,0.11,1.651l0,0c0.424,0.421,1.056,0.36,1.417-0.129l0,0c7.126-9.733,17.123-14.593,27.135-14.594 l0,0c10.01,0.001,20.01,4.861,27.136,14.594l0,0c0.358,0.489,0.992,0.551,1.415,0.129l0,0 c0.419-0.418,0.47-1.157,0.108-1.648l0,0c-7.515-10.27-18.091-15.414-28.653-15.414l0,0 C492.489,387.328,492.488,387.328,492.486,387.328L492.486,387.328z"/> <path fill="#3B1410" d="M520.384,406.376c-0.845,0.004-1.66-0.436-2.141-1.11l0,0c-6.843-9.329-16.304-13.885-25.759-13.893 l0,0c-9.455,0.008-18.914,4.564-25.766,13.906l0,0c-0.482,0.658-1.28,1.102-2.134,1.098l0,0 c-0.685,0.004-1.374-0.29-1.855-0.777l0,0c-0.598-0.603-0.852-1.365-0.855-2.101l0,0c0.003-0.605,0.178-1.225,0.574-1.768 l0,0c0.01-0.016,0.02-0.029,0.032-0.041l0,0c7.799-10.645,18.892-16.077,29.998-16.07l0,0c0.005,0,0.011,0,0.014,0l0,0h0.003 c11.119-0.007,22.229,5.44,30.031,16.115l0,0c0.396,0.546,0.564,1.165,0.567,1.766l0,0c-0.003,0.731-0.251,1.493-0.856,2.103 l0,0c-0.478,0.479-1.151,0.773-1.837,0.773l0,0C520.394,406.376,520.387,406.376,520.384,406.376L520.384,406.376z M492.484,387.957v-0.63l0.336-1.675l-0.336,1.675V387.957L492.484,387.957L492.484,387.957z"/> </g> </g> <g> <g> <path fill="#3B1410" d="M227.415,387.328c-10.562-0.004-21.144,5.141-28.661,15.414l0,0v-0.003 c-0.361,0.493-0.311,1.233,0.112,1.651l0,0c0.419,0.421,1.054,0.36,1.414-0.129l0,0c7.126-9.733,17.124-14.593,27.135-14.594 l0,0c10.011,0.001,20.01,4.861,27.137,14.594l0,0c0.36,0.489,0.993,0.551,1.413,0.129l0,0 c0.423-0.418,0.471-1.157,0.11-1.648l0,0c-7.517-10.27-18.091-15.414-28.652-15.414l0,0 C227.42,387.328,227.415,387.328,227.415,387.328L227.415,387.328z"/> <path fill="#3B1410" d="M255.313,406.376c-0.845,0.004-1.658-0.436-2.14-1.11l0,0c-6.843-9.329-16.303-13.885-25.758-13.893 l0,0c-9.454,0.008-18.915,4.564-25.766,13.906l0,0c-0.481,0.658-1.282,1.102-2.132,1.098l0,0 c-0.69,0.004-1.377-0.29-1.857-0.777l0,0c-0.597-0.603-0.854-1.365-0.855-2.101l0,0c0.001-0.605,0.176-1.225,0.574-1.768l0,0 c0.011-0.016,0.02-0.029,0.029-0.041l0,0c7.799-10.645,18.895-16.077,30.001-16.07l0,0c0.003,0,0.006,0,0.012,0l0,0h0.002 c11.121-0.007,22.231,5.44,30.03,16.115l0,0c0.397,0.546,0.567,1.165,0.57,1.766l0,0c-0.003,0.731-0.254,1.493-0.857,2.103 l0,0c-0.479,0.479-1.151,0.773-1.836,0.773l0,0C255.323,406.376,255.316,406.376,255.313,406.376L255.313,406.376z M227.415,387.957v-0.63l0.335-1.675l-0.335,1.675V387.957L227.415,387.957L227.415,387.957z"/> </g> </g> </g> <g> <path fill="#010101" d="M550.875,438.219c0,0-20.954,15.173-54.19,5.058c0,0-11.385-5.42-24.246-1.27 c-14.925,3.748-25.904,16.404-25.904,31.447c0,17.998,15.711,32.589,35.094,32.589c17.583,0,32.146-12.007,34.695-27.675 C526.478,476.524,544.696,465.739,550.875,438.219z"/> <g> <path fill="#FFFFFF" d="M507.899,468.263c0,5.813-5.136,10.527-11.465,10.527c-6.338,0-11.469-4.714-11.469-10.527 c0-5.815,5.131-10.533,11.469-10.533C502.764,457.729,507.899,462.447,507.899,468.263z"/> <path fill="#FFFFFF" d="M481.926,485.341c0,2.727-2.41,4.939-5.378,4.939c-2.976,0-5.385-2.213-5.385-4.939 c0-2.73,2.409-4.945,5.385-4.945C479.516,480.395,481.926,482.61,481.926,485.341z"/> </g> <g> <path fill="#1B181C" d="M259.35,466.94c-3.782-0.455-7.734,3.301-10.425,7.143c-12.191,18.109-45.449,18.109-57.64,0 c-2.689-3.842-6.639-7.598-10.422-7.143l0,0c-3.764,0.411-5.53,7.023-1.549,12.898c17.254,25.639,64.33,25.639,81.582,0.004 C264.882,473.964,263.113,467.351,259.35,466.94L259.35,466.94z"/> </g> </g> <g> <path fill="#FFFFFF" d="M416.744,544.266c-0.859-1.077-2.08-1.004-2.927,0h-0.332h-56.791h-2.917h-65.42 c-0.833-1.426-2.29-1.211-3.262,0c-0.973,1.221-1.084,3.361-0.253,4.785v-0.006c17.332,29.784,41.724,44.691,66.077,44.691 c0.003,0,0.012,0,0.016,0c24.351,0,48.733-14.914,66.064-44.691C417.83,547.62,417.713,545.487,416.744,544.266z"/> </g> </g> <g> <path fill="#3B1410" d="M645.703,353.759C645.703,143.246,513.84-0.268,341.232,0C171.073,0.262,56.233,143.246,56.233,353.762 c0.002,25.142,15.687,89.017,20.993,101.091c8.953,20.378,48.74,52.87,75.597,91.852 c-31.331-71.765-30.074-146.556-30.074-146.556s159.164,42.443,363.427-161.817c6.581,8.1,94.723,185.055,94.723,185.055 s14.964,48.898-26.22,111.805c0,0,58.79-48.696,71.791-82.74C629.64,444.155,645.703,378.784,645.703,353.759z"/> <g> <linearGradient id="SVGID_16_" gradientUnits="userSpaceOnUse" x1="772.6558" y1="102.7029" x2="985.3578" y2="102.7029" gradientTransform="matrix(-0.9886 0.1505 0.1505 0.9886 1120.4738 -172.6003)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_16_)" d="M370.612,35.554c0,0-104.022-17.74-205.353,64.355 C165.259,99.909,226.619,14.091,370.612,35.554z"/> <linearGradient id="SVGID_17_" gradientUnits="userSpaceOnUse" x1="512.2903" y1="252.9687" x2="620.1285" y2="252.9687" gradientTransform="matrix(-0.966 0.2584 0.2584 0.966 1027.7928 -85.7945)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_17_)" d="M444.598,133.698c0,0,199.351,60.682,159.957,353.938 C604.555,487.635,664.541,190.835,444.598,133.698z"/> <linearGradient id="SVGID_18_" gradientUnits="userSpaceOnUse" x1="515.6821" y1="87.2381" x2="607.4606" y2="87.2381" gradientTransform="matrix(-1.0087 0.3502 0.3689 1.0625 1087.8507 -44.2152)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_18_)" d="M450.007,96.23c0,0,148.743-5.351,178.487,307.761 C628.494,403.992,628.494,93.555,450.007,96.23z"/> <linearGradient id="SVGID_19_" gradientUnits="userSpaceOnUse" x1="536.4581" y1="146.1406" x2="817.6895" y2="146.1406" gradientTransform="matrix(-0.9989 -0.0467 -0.0467 0.9989 946.2015 19.9831)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_19_)" d="M406.495,77.037c0,0-172.367-42.429-287.129,119.639 C119.366,196.676,201.697,31.43,406.495,77.037z"/> <linearGradient id="SVGID_20_" gradientUnits="userSpaceOnUse" x1="591.3597" y1="-28.2471" x2="861.3224" y2="-28.2471" gradientTransform="matrix(-1.1164 0.6519 0.5042 0.8635 1091.2041 -164.2081)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_20_)" d="M411.38,187.68c0,0-161.863,41.268-281.583,209.904 C129.797,397.584,181.288,256.429,411.38,187.68z"/> <linearGradient id="SVGID_21_" gradientUnits="userSpaceOnUse" x1="349.0724" y1="137.6138" x2="680.7399" y2="137.6138" gradientTransform="matrix(-0.9695 0.0633 0.0406 0.9072 744.6884 137.8341)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_21_)" d="M403.851,106.052c0,0-354.125-2.575-299.329,378.656 C104.523,484.708,10.224,113.738,403.851,106.052z"/> <linearGradient id="SVGID_22_" gradientUnits="userSpaceOnUse" x1="263.0153" y1="43.7536" x2="650.2787" y2="43.7536" gradientTransform="matrix(-0.8219 0.1065 0.1225 0.945 627.7811 182.8543)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_22_)" d="M404.034,152.432c0,0-221.758,21.408-292.069,243.532 C111.965,395.964,166.053,152.432,404.034,152.432z"/> <linearGradient id="SVGID_23_" gradientUnits="userSpaceOnUse" x1="493.9396" y1="49.7161" x2="599.5733" y2="49.7161" gradientTransform="matrix(-1.0087 0.3502 0.3689 1.0625 1087.8507 -44.2152)"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_23_)" d="M445.947,58.859c0,0,177.139,21.317,198.777,288.934 C644.724,347.793,636.608,69.47,445.947,58.859z"/> <linearGradient id="SVGID_24_" gradientUnits="userSpaceOnUse" x1="152.8603" y1="376.5605" x2="427.4074" y2="232.4359"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_24_)" d="M421.858,221.865c0,0-221.559,70.727-254.911,181.531 C166.948,403.396,214.597,264.301,421.858,221.865z"/> <linearGradient id="SVGID_25_" gradientUnits="userSpaceOnUse" x1="202.8852" y1="394.3258" x2="457.3486" y2="260.7443"> <stop offset="0" style="stop-color:#3B1410"/> <stop offset="0.1834" style="stop-color:#502919"/> <stop offset="0.533" style="stop-color:#835321"/> <stop offset="1" style="stop-color:#3B1410"/> </linearGradient> <path fill="url(#SVGID_25_)" d="M448.387,243.673c0,0-121.501,124.95-245.381,150.882 C203.006,394.556,341.183,382.768,448.387,243.673z"/> </g> </g> </g> </g> </g> </svg> </div></a> <div class="filters" ng-show="type=='dir'"> <h2>Filter by date</h2> <ul> <li class="filter" ng-class="{enabled: filterCheck('dates',key)}" ng-click="filter('dates',key)" ng-repeat="(key, val) in dateFilterNames"><span class="filter-name">{{val}}</span><span class="item-count">({{dates[key] || '0'}})</span></li> </ul> <br><br> <h2>Filter by type</h2> <ul> <li class="filter" ng-class="{enabled: filterCheck('types',key)}" ng-click="filter('types',key)" ng-repeat="(key, val) in types"><span class="filter-name">{{key}}</span><span class="item-count">({{val}})</span></li> </ul> <br><br> <h2>Sort by</h2> <ul> <li class="filter">Name</li> <li class="filter">Date</li> <li class="filter">Type</li> </ul> </div> <div class="details" ng-show="type!='dir'"> <h2>File info</h2> <ul> <li class="info">Created: {{file.ctime*1000 | date:'medium'}}</li> <li class="info">Modified: {{file.mtime*1000 | date:'medium'}}</li> <li class="info">Size: {{file.sizeReadable}}</li> <li class="info" ng-repeat="(key, val) in file.meta">{{key}}: <b>{{val}}</b></li> </ul> </div> </div> <div class="toggles"> <button ng-class="{enabled: filters.recursive == 0}" ng-click="filter('recursive',0)">Browse</button> <button ng-class="{enabled: filters.recursive == 1}" ng-click="filter('recursive',1)">Recent</button> <div class="search" ng-class="{active: searchActive}"> <i class="fa fa-search"></i> <input type="text" class="search-box" ng-model="filters.search" ng-focus="searchActive=true" ng-blur="searchActive=false" placeholder="Search"> </div> </div> <div class="content"> <div class="location"> <h1> <i class="fa fa-folder-open"></i> <input ng-model="file.name" ng-show="file.writeable && file.name" ng-file-name><span class="file-name-top" ng-show="!file.name || !file.writeable">{{file.name || 'Home'}}</span> </h1> <a href="{{path()}}{{file.path}}" class="path">{{file.path ? 'Home' + (file.path == '/' ? '' : file.path) : ''}}</a> </div> <div class="actions"> <button title="Fullscreen editor" class="fullscreen-button" ng-show="file.writeable && file.name && type!='dir' && file.type == 'text'" ng-fullscreen-editor><i class="fa fa-expand"></i></button><?php ?><button title="Save this file" class="save-button" ng-save ng-show="file.writeable && file.name && type!='dir' && file.type == 'text'"><i class="fa fa-floppy-o"></i></button><?php ?><button title="Delete this {{type=='dir' ? 'folder' : 'file'}}" class="delete-button" ng-delete ng-show="file.writeable && file.name"><i class="fa fa-trash-o"></i></button><?php ?><a href="#NewFile"><button title="Create a new file" class="create-file-button" ng-make-file ng-show="file.writeable && type=='dir'"><i class="fa fa-file-text"></i></button></a><?php ?><button title="Create a new folder" class="create-folder-button" ng-make-dir ng-show="file.writeable && type=='dir'"><i class="fa fa-folder"></i></button><?php ?><button title="Upload a file" class="upload-button" ng-upload ng-show="file.writeable && type=='dir'"><i class="fa fa-cloud-upload"></i></button> </div> <div class="uploads" ng-show="type=='dir'"> <a class="file upload-item clearfix" ng-repeat="upload in uploads"> <div class="progress progress-striped active "> <div class="progress-bar" ng-class="{'progress-bar-info': upload.status == 'uploading', 'progress-bar-danger': upload.status == 'error', 'progress-bar-success': upload.status == 'success'}" style="width: {{upload.progress}}%"></div> </div> <div class="upload-content"> <div class="icon"> <i class="fa fa-cloud-upload"></i> </div> <div class="fileinfo"> <span class="filename">{{upload.name}}</span> <span class="path"><br>Home{{upload.path}}</span> </div> <span class="attrs"> {{upload.sizeReadable}}<br> <b ng-show="upload.status == 'success'">Complete!</b> <b ng-show="upload.status == 'error'">Failed to upload</b> </span> </div> </a> </div> <div class="files" ng-show="type=='dir'"> <a href="{{path()}}{{file.path}}/{{file.name}}" class="file" ng-repeat="file in dirs | filter:filterFolders" tabindex="1" ng-show="!filters.recursive"> <i class="icon fa fa-folder-o"></i> <div class="fileinfo"> <span class="filename">{{file.name}}</span> <span class="path"><br>Home{{file.path}}</span> </div> </a> <a href="{{path()}}{{file.path}}/{{file.name}}" class="file" ng-repeat="file in files | filter:filterFiles" tabindex="1" > <div class="icon" ng-click="downloadFile($event, file)"> <i class="fa fa-file-text-o"></i> <i class="fa fa-download"></i> </div> <div class="fileinfo"> <span class="filename">{{file.name}}</span> <span class="path"><br>Home{{file.path}}</span> </div> <span class="attrs"> {{file.dateReadable}}<br> {{file.sizeReadable}} </span> </a> </div> <div class="file-contents" ng-show="type!='dir'"> <div id="editor" ng-show="file.contents"></div> <?php /*<div class="file-image" style="background: url(/Files/{{file.path}}/{{file.name}})"></div> */ ?> </div> </div> <div class="copyright"> <a href="http://cheryl.io" target="_blank"><span class="powered">powered by</span> <span class="cheryl">cheryl.io</span></a> </div> </div> <div class="login-wrap" ng-show="!authed"> <div class="login"> <form ng-submit="login()"> <div class="welcome fadeInDown animated" ng-bind="welcome">Welcome!</div> <div class="login-form fadeIn animated"> <div class="input-wrap"> <span class="label">Username:</span> <span class="field"><input type="text" ng-model="user.username" autofocus></span> </div> <div class="input-wrap"> <span class="label">Password:</span> <span class="field"><input type="password" ng-model="user.password"></span> </div> <button class="login-button" type="submit"><i class="fa fa-heart"></i> Login</button> </div> </form> <div class="copyright-login"> <a href="http://cheryl.io" target="_blank"><span class="powered">powered by</span> <span class="cheryl">cheryl.io</span></a> </div> </div> </div> <div class="modal-wrap" ng-modal> <div class="modal modal-{{dialog.type}}"> <div ng-show="dialog.type == 'makeDir'"> <form ng-submit="dialog.yes()"> <h2>Create a folder in <b>Home{{file.path ? (file.path == '/' ? '' : file.path) : ''}}{{file.path ? '/' : ''}}{{file.name}}</b> <br><br> <input type="text" ng-model="dialog.file" ng-autofocus="dialog.type == 'makeDir'"> </h2> <br><br><br> <button type="submit">Make</button> <button ng-click="dialog.no()">Cancel</button> </form> </div> <div ng-show="dialog.type == 'confirmDelete'"> <h2>Are you sure you want to delete <b>{{dialog.file.name}}</b>?</h2> <br><br><br> <form ng-submit="dialog.yes()"> <button ng-autofocus="dialog.type == 'confirmDelete'" tabindex="20">Yes</button> <button ng-click="dialog.no()" tabindex="21">No</button> </form> </div> <div ng-show="dialog.type == 'error'"> <h2>{{dialog.message}}</h2> <br><br><br> <form ng-submit="dialog=false"> <button ng-autofocus="dialog.type == 'error'">Close</button> </form> </div> <div ng-show="dialog.type == 'dropupload'"> <h1><i class="fa fa-cloud-upload"></i></h1> <h2>Drop it!</h2> </div> </div> </div> <iframe id="downloader"></iframe> <input type="file" class="upload" ng-uploader multiple> </body> <script src="_assets/angular.min.js"></script> <script src="_assets/angular-route.min.js"></script> <script src="_assets/ace.js"></script> <script> /* http://caligatio.github.com/jsSHA/ */ (function(module) {function k(d){throw d;}function s(d,f){var a=[],b,c=[],e=0,g;if("UTF8"==f)for(g=0;g<d.length;g+=1){b=d.charCodeAt(g);c=[];2048<b?(c[0]=224|(b&61440)>>>12,c[1]=128|(b&4032)>>>6,c[2]=128|b&63):128<b?(c[0]=192|(b&1984)>>>6,c[1]=128|b&63):c[0]=b;for(b=0;b<c.length;b+=1)a[e>>>2]|=c[b]<<24-8*(e%4),e+=1}else if("UTF16"==f)for(g=0;g<d.length;g+=1)a[e>>>2]|=d.charCodeAt(g)<<16-8*(e%4),e+=2;return{value:a,binLen:8*e}} function u(d){var f=[],a=d.length,b,c;0!==a%2&&k("String of HEX type must be in byte increments");for(b=0;b<a;b+=2)c=parseInt(d.substr(b,2),16),isNaN(c)&&k("String of HEX type contains invalid characters"),f[b>>>3]|=c<<24-4*(b%8);return{value:f,binLen:4*a}} function v(d){var f=[],a=0,b,c,e,g,h;-1===d.search(/^[a-zA-Z0-9=+\/]+$/)&&k("Invalid character in base-64 string");b=d.indexOf("=");d=d.replace(/\=/g,"");-1!==b&&b<d.length&&k("Invalid '=' found in base-64 string");for(c=0;c<d.length;c+=4){h=d.substr(c,4);for(e=g=0;e<h.length;e+=1)b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf(h[e]),g|=b<<18-6*e;for(e=0;e<h.length-1;e+=1)f[a>>2]|=(g>>>16-8*e&255)<<24-8*(a%4),a+=1}return{value:f,binLen:8*a}} function w(d,f){var a="",b=4*d.length,c,e;for(c=0;c<b;c+=1)e=d[c>>>2]>>>8*(3-c%4),a+="0123456789abcdef".charAt(e>>>4&15)+"0123456789abcdef".charAt(e&15);return f.outputUpper?a.toUpperCase():a} function x(d,f){var a="",b=4*d.length,c,e,g;for(c=0;c<b;c+=3){g=(d[c>>>2]>>>8*(3-c%4)&255)<<16|(d[c+1>>>2]>>>8*(3-(c+1)%4)&255)<<8|d[c+2>>>2]>>>8*(3-(c+2)%4)&255;for(e=0;4>e;e+=1)a=8*c+6*e<=32*d.length?a+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(g>>>6*(3-e)&63):a+f.b64Pad}return a} function y(d){var f={outputUpper:!1,b64Pad:"="};try{d.hasOwnProperty("outputUpper")&&(f.outputUpper=d.outputUpper),d.hasOwnProperty("b64Pad")&&(f.b64Pad=d.b64Pad)}catch(a){}"boolean"!==typeof f.outputUpper&&k("Invalid outputUpper formatting option");"string"!==typeof f.b64Pad&&k("Invalid b64Pad formatting option");return f}function z(d,f){var a=(d&65535)+(f&65535);return((d>>>16)+(f>>>16)+(a>>>16)&65535)<<16|a&65535} function A(d,f,a,b,c){var e=(d&65535)+(f&65535)+(a&65535)+(b&65535)+(c&65535);return((d>>>16)+(f>>>16)+(a>>>16)+(b>>>16)+(c>>>16)+(e>>>16)&65535)<<16|e&65535} function B(d,f){var a=[],b,c,e,g,h,C,t,j,D,l=[1732584193,4023233417,2562383102,271733878,3285377520],n=[1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1518500249,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393,1859775393, 1859775393,1859775393,1859775393,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,2400959708,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782,3395469782];d[f>>>5]|=128<<24-f%32;d[(f+ 65>>>9<<4)+15]=f;D=d.length;for(t=0;t<D;t+=16){b=l[0];c=l[1];e=l[2];g=l[3];h=l[4];for(j=0;80>j;j+=1)a[j]=16>j?d[j+t]:(a[j-3]^a[j-8]^a[j-14]^a[j-16])<<1|(a[j-3]^a[j-8]^a[j-14]^a[j-16])>>>31,C=20>j?A(b<<5|b>>>27,c&e^~c&g,h,n[j],a[j]):40>j?A(b<<5|b>>>27,c^e^g,h,n[j],a[j]):60>j?A(b<<5|b>>>27,c&e^c&g^e&g,h,n[j],a[j]):A(b<<5|b>>>27,c^e^g,h,n[j],a[j]),h=g,g=e,e=c<<30|c>>>2,c=b,b=C;l[0]=z(b,l[0]);l[1]=z(c,l[1]);l[2]=z(e,l[2]);l[3]=z(g,l[3]);l[4]=z(h,l[4])}return l} module.jsSHA=function(d,f,a){var b=null,c=0,e=[0],g="",h=null,g="undefined"!==typeof a?a:"UTF8";"UTF8"===g||"UTF16"===g||k("encoding must be UTF8 or UTF16");"HEX"===f?(0!==d.length%2&&k("srcString of HEX type must be in byte increments"),h=u(d),c=h.binLen,e=h.value):"ASCII"===f||"TEXT"===f?(h=s(d,g),c=h.binLen,e=h.value):"B64"===f?(h=v(d),c=h.binLen,e=h.value):k("inputFormat must be HEX, TEXT, ASCII, or B64");this.getHash=function(a,d,f){var g=null,h=e.slice(),n="";switch(d){case "HEX":g=w;break;case "B64":g= x;break;default:k("format must be HEX or B64")}"SHA-1"===a?(null===b&&(b=B(h,c)),n=g(b,y(f))):k("Chosen SHA variant is not supported");return n};this.getHMAC=function(b,a,d,f,h){var n,p,m,E,r,F,G=[],H=[],q=null;switch(f){case "HEX":n=w;break;case "B64":n=x;break;default:k("outputFormat must be HEX or B64")}"SHA-1"===d?(m=64,F=160):k("Chosen SHA variant is not supported");"HEX"===a?(q=u(b),r=q.binLen,p=q.value):"ASCII"===a||"TEXT"===a?(q=s(b,g),r=q.binLen,p=q.value):"B64"===a?(q=v(b),r=q.binLen,p= q.value):k("inputFormat must be HEX, TEXT, ASCII, or B64");b=8*m;a=m/4-1;m<r/8?("SHA-1"===d?p=B(p,r):k("Unexpected error in HMAC implementation"),p[a]&=4294967040):m>r/8&&(p[a]&=4294967040);for(m=0;m<=a;m+=1)G[m]=p[m]^909522486,H[m]=p[m]^1549556828;"SHA-1"===d?E=B(H.concat(B(G.concat(e),b+c)),b+F):k("Unexpected error in HMAC implementation");return n(E,y(h))}};})(this); </script> <script>var editor; var Cheryl = angular.module('Cheryl', ['ngRoute']) .config(function($routeProvider){ $routeProvider .when('/logout', { action: 'logout', controller: 'LogoutCtrl', }) .when('/login', { action: 'login', controller: 'LoginCtrl', }) .otherwise({ action: 'home', controller: 'RootCtrl' }); }) // Convert angulars json payload to the querystring standard so old versions of apache/php can understand .config(function($httpProvider) { $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8'; $httpProvider.defaults.transformRequest = [function(data) { var param = function(obj) { var query = ''; var name, value, fullSubName, subValue, innerObj, i; for (name in obj) { value = obj[name]; if (value instanceof Array || value instanceof Object) { for (var subName in value) { innerObj = {}; innerObj[name + '[' + subName + ']'] = value[subName]; query += param(innerObj) + '&'; } } else if(value !== undefined && value !== null) { query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&'; } } return query.length ? query.substr(0, query.length - 1) : query; }; return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data; }]; }) .config(function($locationProvider){ $locationProvider.html5Mode(true).hashPrefix('!'); }) .controller('RootCtrl', function ($scope, $http, $location, $anchorScroll, $route) { $scope.now = new Date; $scope.yesterday = new Date; $scope.yesterday.setDate($scope.yesterday.getDate() - 1); $scope.user = []; $scope.welcomeDefault = $scope.welcome = 'Welcome!'; $scope.types = []; $scope.dates = []; $scope.type = 'dir'; $scope.dialog = false; $scope.config = false; $scope.dateFormat = 'm/d/Y H:i:s'; $scope.path = function() { return $scope.script; }; $scope.dirPath = function() { return $location.path().replace($scope.script,'') || '/'; }; var password = function() { return encodeURIComponent(new jsSHA($scope.user.password + '<?php echo CHERYL_SALT; ?>', 'TEXT').getHash('SHA-1', 'HEX')); }; $scope.getConfig = function() { $http({method: 'GET', url: $scope.path() + '?__p=config'}). success(function(data) { if (data.status) { $scope.authed = data.authed; $scope.config = true; } }); }; $scope.login = function() { $http.post($scope.path() + '/', {'__p': 'login', '__username': $scope.user.username, '__hash': password()}). success(function(data) { if (data.status) { $scope.welcome = $scope.welcomeDefault; $scope.authed = true; $scope.user.password = ''; } else { $scope.welcome = 'Try again!'; } }). error(function(data) { $scope.welcome = 'Try again!'; }); }; $scope.authed = false; $scope.script = '<?php echo Cheryl::script() ?>'; $scope.dateFilterNames = { 0: 'Today', 1: 'Last week', 2: 'Last month', 3: 'Archive' }; $scope.filters = { recursive: 0, types: [], dates: [], search: '' }; $scope.uploads = []; $scope.filter = function(filter, value) { switch (filter) { case 'recursive': $scope.filters[filter] = value; break; case 'types': case 'dates': $scope.filters[filter][value] = !$scope.filters[filter][value]; var hasValue = false; for (var x in $scope.filters[filter]) { if ($scope.filters[filter][x]) { hasValue = true; break; } } if (!hasValue) { $scope.filters[filter] = []; } break; } }; $scope.filterFiles = function(file) { if (Object.size($scope.filters.types)) { if (!$scope.filters.types[file.ext.toUpperCase()]) { return false; } } if (Object.size($scope.filters.dates)) { if (!$scope.filters.dates[file.dateFilter]) { return false; } } if ($scope.filters.search && file.name.indexOf($scope.filters.search) === -1) { return false; } return true; }; $scope.filterFolders = function(file) { if ($scope.filters.search && file.name.indexOf($scope.filters.search) === -1) { return false; } return true; }; $scope.filterCheck = function(filter, value) { return $scope.filters[filter][value]; }; var formatDate = function(file) { var time = new Date(file.mtime * 1000); var timeOfDay = (time.getHours() > 12 ? time.getHours() - 12 : time.getHours()) + ':' + time.getMinutes() + (time.getHours() > 12 ? ' PM' : ' AM'); var daysAgo = Math.ceil(($scope.now.getTime() / 1000 / 60 / 60 / 24) - (time.getTime() / 1000 / 60 / 60 / 24)); if ('' + time.getFullYear() + time.getMonth() + time.getDate() == '' + $scope.now.getFullYear() + $scope.now.getMonth() + $scope.now.getDate()) { file.dateReadable = 'Today @ ' + timeOfDay; file.dateFilter = 0; } else if ('' + time.getFullYear() + time.getMonth() + time.getDate() == '' + $scope.yesterday.getFullYear() + $scope.yesterday.getMonth() + $scope.yesterday.getDate()) { file.dateReadable = 'Yesterday @ ' + timeOfDay; file.dateFilter = 1; } else if (daysAgo < 7) { file.dateReadable = daysAgo + ' day' + (daysAgo == 1 ? '' : 's') + ' ago'; file.dateFilter = 1; } else if (daysAgo < 28) { var weeks = Math.floor(daysAgo / 7); file.dateReadable = weeks + ' week' + (weeks == 1 ? '' : 's') + ' ago'; file.dateFilter = 2; } else if (daysAgo < 363) { var months = Math.floor(daysAgo / 30); file.dateReadable = months + ' month' + (months == 1 ? '' : 's') + ' ago'; file.dateFilter = 3; } else { var years = Math.floor(daysAgo / 365); file.dateReadable = years + ' year' + (years == 1 ? '' : 's') + ' ago'; file.dateFilter = 3; } $scope.dates[file.dateFilter] = $scope.dates[file.dateFilter] ? $scope.dates[file.dateFilter] + 1 : 1; }; $scope.formatSize = function(file) { var size = file.size; var i = -1; var byteUnits = [' KB', ' MB', ' GB', ' TB', 'PB', 'EB', 'ZB', 'YB']; do { size = size / 1024; i++; } while (size > 1024); file.sizeReadable = Math.max(size, 0.1).toFixed(1) + byteUnits[i]; }; $scope.loadFiles = function() { if (!$scope.config) { $scope.getConfig(); return; } if (!$scope.authed) { return; } $scope.fullscreenEdit = false; $scope.filters.search = ''; var url = $scope.path() + '?__p=ls&_d=' + $scope.dirPath(); for (var x in $scope.filters) { url += '&filters[' + x + ']=' + $scope.filters[x]; } $http({method: 'GET', url: url}). success(function(data) { $scope.type = data.type; $scope.file = data.file; $scope.file.nameUser = $scope.file.name; if (data.type == 'dir') { $scope.files = data.list.files; $scope.dirs = data.list.dirs; $scope.types = {}; $scope.dates = {}; for (var x in $scope.files) { var type = $scope.files[x].ext.toUpperCase(); $scope.types[type] = $scope.types[type] ? $scope.types[type]+1 : 1; formatDate($scope.files[x]); $scope.formatSize($scope.files[x]); } } else { formatDate($scope.file); $scope.formatSize($scope.file); } }). error(function() { $scope.files = null; }); }; $scope.$watch('filters.recursive', $scope.loadFiles); $scope.$watch('authed', $scope.loadFiles); $scope.$on('$locationChangeSuccess', function() { $anchorScroll(); switch ($location.$$hash) { case 'NewFile': break; default: $scope.loadFiles(); break; } }); $scope.modes = { php: 'php', js: 'javascript', css: 'css', md: 'markdown', svg: 'svg', xml: 'xml', asp: 'asp', c: 'c', sql: 'mysql' }; $scope.$watch('file.contents', function() { if (!$scope.file || !$scope.file.contents) { return; } if (!$scope.editor) { $scope.editor = ace.edit('editor'); $scope.editor.renderer.setShowPrintMargin(false); $scope.editor.session.setWrapLimitRange(null, null); $scope.editor.commands.addCommand({ name: 'saveFile', bindKey: { win: 'Ctrl-S', mac: 'Command-S', sender: 'editor|cli' }, exec: function(env, args, request) { $scope.saveFile(); } }); } var mode = 'text'; for (var x in $scope.modes) { if (x == $scope.file.ext) { mode = $scope.modes[x]; break; } } $scope.editor.getSession().setMode('ace/mode/' + mode); $scope.editor.getSession().setValue($scope.file.contents); $scope.editor.setReadOnly(!$scope.file.writeable); fullscreenToggle(); }); var fullscreenToggle = function() { if (!$scope.editor) { return; } if ($scope.fullscreenEdit) { $scope.editor.renderer.setShowGutter(true); $scope.editor.setHighlightActiveLine(true); $scope.editor.session.setUseWrapMode(false); $scope.editor.setTheme('ace/theme/ambiance'); } else { $scope.editor.renderer.setShowGutter(false); $scope.editor.setHighlightActiveLine(false); $scope.editor.session.setUseWrapMode(true); $scope.editor.setTheme('ace/theme/clouds'); } setTimeout(function(){ $scope.editor.resize(); }); }; $scope.$watch('fullscreenEdit', fullscreenToggle); $scope.$watch('file.nameUser', function() { if (!$scope.file || $scope.file.name == $scope.file.nameUser) { return; } console.log('CHANGED'); }); $scope.downloadFile = function(event, file) { event.preventDefault(); event.stopPropagation(); var iframe = document.getElementById('downloader'); iframe.src = $scope.path() + '?__p=dl&_d=' + file.path + '/' + file.name; }; $scope.saveFile = function() { $scope.$apply(function() { var error = function() { $scope.dialog = {type: 'error', message: 'There was an error saving the file.'}; }; $http.post($scope.path() + '/', { '__p': 'sv', '_d': $scope.dirPath(), 'c': $scope.editor.getSession().getValue() }). success(function(data) { if (data.status) { $scope.dialog = false; } else { error(); } }). error(error); }); }; $scope.upload = function(event, scope) { var files = event.target.files || event.dataTransfer.files; for (var i = 0, f; f = files[i]; i++) { var xhr = new XMLHttpRequest(); var file = files[i]; if (xhr.upload && file.size <= 9000000000) { var fd = new FormData(); fd.append(file.name, file); scope.$apply(function() { var upload = { name: file.name, path: $location.path(), size: file.size, uploaded: 0, progress: 0, status: 'uploading' }; scope.formatSize(upload); scope.uploads.push(upload); xhr.upload.addEventListener('progress', function(e) { scope.$apply(function() { upload.uploaded = e.loaded; upload.progress = parseInt(e.loaded / e.total * 100); }); }, false); xhr.onload = function() { var status = this.status; scope.$apply(function() { upload.status = (status == 200 ? 'success' : 'error'); scope.loadFiles(); }); setTimeout(function() { scope.$apply(function() { scope.uploads.splice(scope.uploads.indexOf(upload), 1); }); },5000); }; xhr.open('POST', scope.path() + '/?__p=ul&_d=' + scope.dirPath(), true); xhr.setRequestHeader('X-File-Name', file.name); xhr.send(fd); }); } } }; }) .directive('ngEnter', function() { return function(scope, element, attrs) { if (attrs.ngEnter) { element.bind('keydown keypress', function(event) { if (event.which === 13) { event.preventDefault(); scope.$eval(attrs.ngEnter); } }); } }; }) .directive('ngDropUpload', function () { return function (scope, element) { var dragEnd = function() { scope.$apply(function() { scope.dialog = false; }); }; var autoEndClean; angular.element(document).bind('dragover', function(event) { clearTimeout(autoEndClean); for (var x in event.dataTransfer.files) { console.log(event.dataTransfer.files[x]); } event.preventDefault(); scope.$apply(function() { scope.dialog = { type: 'dropupload' } }); autoEndClean = setTimeout(dragEnd,1000); }); element .bind('drop', function(event) { event.preventDefault(); scope.upload(event, scope); }); } }) .directive('ngUploader', function($location) { return function(scope, element) { element.bind('change', function(event) { scope.upload(event, scope); }); }; }) .directive('ngUpload', function() { return function(scope, element) { element.bind('click', function(event) { document.querySelector('.upload').click(); }); }; }) .directive('ngMakeDir', function($http, $location) { return function(scope, element) { element.bind('click', function(event) { scope.$apply(function() { scope.dialog = { type: 'makeDir', path: scope.file, file: '', no: function() { scope.dialog = false; }, yes: function() { if (!scope.dialog.file) { return; } var error = function() { scope.dialog = {type: 'error', message: 'There was an error creating the folder.'}; }; $http({method: 'GET', url: scope.path() + '?__p=mk&_d=' + scope.dirPath() + '&_n=' + scope.dialog.file}). success(function(data) { if (data.status) { scope.dialog = false; scope.loadFiles(); } else { error(); } }). error(error); } }; }); }); }; }) .directive('ngDelete', function($http, $location) { return function(scope, element) { element.bind('click', function(event) { scope.$apply(function() { scope.dialog = { type: 'confirmDelete', file: scope.file, no: function() { scope.dialog = false; }, yes: function() { var error = function() { scope.dialog = {type: 'error', message: 'There was an error deleting the ' + (scope.type == 'dir' ? 'folder' : 'file') + '.'}; }; $http({method: 'GET', url: scope.path() + '?__p=rm&_d=' + scope.dirPath()}). success(function(data) { if (data.status) { scope.dialog = false; $location.path(scope.script + scope.file.path); } else { error(); } }). error(error); } }; }); }); }; }) .directive('ngSave', function($http, $location) { return function(scope, element) { element.bind('click', function(event) { scope.saveFile(); }); }; }) .directive('ngFullscreenEditor', function($http, $location) { return function(scope, element) { element.bind('click', function(event) { scope.$apply(function() { scope.fullscreenEdit = true; }); }); }; }) .directive('ngModal', function() { return function(scope, element) { element.bind('click', function(event) { if (event.target == element[0]) { scope.$apply(function() { scope.dialog = false; }); } }); }; }) .directive('ngBody', function() { return function(scope, element) { element.bind('keydown keypress', function(event) { if (event.which == 27) { scope.$apply(function() { scope.dialog = false; scope.fullscreenEdit = false; }); } }); }; }) .directive('ngAutofocus', function() { return function(scope, element, attrs) { if (attrs.ngAutofocus) { scope.$watch(attrs.ngAutofocus, function(value) { setTimeout(function() { element[0].focus(); },10); }); } }; }) .directive('ngFileName', function($http) { return function(scope, element) { var save = function() { var error = function() { scope.dialog = {type: 'error', message: 'There was an error renaming the file.'}; }; $http({method: 'GET', url: scope.path() + '?__p=rn&_d=' + scope.dirPath() + '&_n=' + scope.file.name}). success(function(data) { console.log(data); if (data.status) { } else { error(); } }). error(error); }; element .bind('change', function(event) { clearTimeout(scope.nameChange); scope.nameChange = setTimeout(save, 1000); }) .bind('blur', function(event) { save(); }); }; }); Object.size = function(obj) { var size = 0, key; for (key in obj) { if (obj.hasOwnProperty(key)) size++; } return size; }; </script> </html> <?php $res = ob_get_contents(); ob_end_clean(); } return $res; } } } if (!class_exists('Cheryl_User')) { class Cheryl_User extends Cheryl_User_Base { public static function users() { return Cheryl::me()->config->users; } public function __construct($u) { if (is_string($u)) { $type = strtolower(Cheryl::me()->config->authentication->type); if ($type == 'simple') { foreach (self::users() as $user) { if ($user->username == $u) { $u = $user; break; } } } elseif ($type == 'pdo' && class_exists('PDO')) { $q = Cheryl::me()->config->authentication->pdo->prepare('SELECT * FROM '.Cheryl::me()->config->authentication->permission_table.' WHERE user=:username'); $q->bindValue(':username', $u, PDO::PARAM_STR); $q->execute(); $rows = $q->fetchAll(PDO::FETCH_ASSOC); $u = array( 'user' => $u, 'permissions' => $rows ); } elseif ($type == 'mysql' && function_exists('mysql_connect')) { // @todo #18 } } parent::__construct($u); } public static function login() { if (Cheryl::me()->request['__username']) { // log in attempt if (Cheryl::me()->request['__hash']) { $pass = Cheryl::me()->request['__hash']; } else { $pass = self::password(Cheryl::me()->request['__password']); } } else { return false; } $type = strtolower(Cheryl::me()->config->authentication->type); // simple authentication. store users in an array if ($type == 'simple') { foreach (self::users() as $user) { if ($user->username == Cheryl::me()->request['__username']) { $u = $user; break; } } if ($u && (!$u->password || $pass == $u->password)) { // successfuly send username and password return new Cheryl_User($u); } return false; // use php data objects only if we have the libs } elseif ($type == 'pdo' && class_exists('PDO')) { $q = Cheryl::me()->config->authentication->pdo->prepare('SELECT * FROM '.Cheryl::me()->config->authentication->user_table.' WHERE user=:username AND hash=:hash LIMIT 1'); $q->bindValue(':username', Cheryl::me()->request['__username'], PDO::PARAM_STR); $q->bindValue(':hash', $pass, PDO::PARAM_STR); $q->execute(); $rows = $q->fetchAll(PDO::FETCH_ASSOC); if (count($rows)) { return new Cheryl_User($rows[0]); } // use php data objects only if we have the libs } elseif ($type == 'mysql' && function_exists('mysql_connect')) { // @todo #18 } else { return false; } } } } class Cheryl_User_Base { public function __construct($u = null) { if (is_array($u)) { foreach ($u as $key => $value) { $this->{$key} = $value; } } elseif(is_object($u)) { foreach (get_object_vars($u) as $key => $value) { $this->{$key} = $value; } } elseif (is_string($u)) { } } public static function users() { return array(); } public static function login() { return false; } public function permission($permission) { if ($this->permissions == 'all' || is_array($this->permissions) && $this->permissions[$perimssions] || is_object($this->permissions) && $this->permissions->{$perimssions}) { return true; } else { return false; } } } // if this wasnt defined, then automaticly run the script asuming this is standalone if (!defined('CHERYL_CONTROL')) { $cheryl = new Cheryl(); $cheryl->go(); }