rel_path = Filemanager::cleanPath($get['path']); if ( $this->rel_path != "/ ") { $this->rel_path .= "/"; } if ( ! empty( $get['query'] ) ) { $this->query = $get['query']; } if ( ! empty($get['options'] ) ) { $this->foptions = $get['options']; } $this->root = $get['root']; if ( $this->isAbsPath( $get['path'] ) ) { $this->path = Filemanager::cleanPath($get['path']); } else { $this->root .= '/'; $this->path = $this->root . Filemanager::cleanPath( $get['path'] ); } // Search if ( ! empty( $post['search_string'] ) ) { $this->search_string = ($post['search_string']); } if ( ! empty( $post['search_file_type'] ) ) { $this->search_file_type = ($post['search_file_type']); } // Create if ( ! empty($get['type'] ) ) { $this->type = $get['type']; } // Modify\Create if ( ! empty( $get['new_name'] ) ) { $this->new_name = $get['new_name']; } foreach ( array( 'content', 'mtime', 'patch' ) as $key ) { if ( ! empty( $post[$key] ) ) { if ( get_magic_quotes_gpc() ) { $this->$key = stripslashes( $post[$key] ); } else { $this->$key = $post[$key]; } } } // Duplicate if ( ! empty( $get['destination'] ) ) { $get['destination'] = Filemanager::cleanPath( $get['destination'] ); if ( $this->isAbsPath( $get['path'] ) ) { $i = 1; $this->destination = $get['destination']; do { if( is_dir( $this->destination ) ) { $this->destination = $get['destination'] . " $i"; } elseif( is_file( $this->destination ) ) { $path_parts = pathinfo( $this->destination ); if( isset( $path_parts["extension"] ) ) { $this->destination = str_replace( ".{$path_parts["extension"]}", " {$i}.{$path_parts["extension"]}", $get['destination'] ); } else { $this->destination = $get['destination'] . " $i"; } } $i++; } while( ( is_file( $this->destination ) || is_dir( $this->destination ) ) ); } else { $i = 1; $this->destination = $this->root . $get['destination']; do { if( is_dir( $this->destination ) ) { $this->destination = $this->root . $get['destination'] . " $i"; } elseif( is_file( $this->destination ) ) { $path_parts = pathinfo( $this->destination ); if( isset( $path_parts["extension"] ) ) { $this->destination = str_replace( ".{$path_parts["extension"]}", " {$i}.{$path_parts["extension"]}", $this->root . $get['destination'] ); } else { $this->destination = $this->root . $get['destination'] . " $i"; } } $i++; } while( ( is_file( $this->destination ) || is_dir( $this->destination ) ) ); } } } ////////////////////////////////////////////////////////////////// // INDEX (Returns list of files and directories) ////////////////////////////////////////////////////////////////// public function index() { if ( file_exists( $this->path ) ) { $index = array(); if ( is_dir( $this->path ) && $handle = opendir( $this->path ) ) { while (false !== ( $object = readdir( $handle ) ) ) { if ($object != "." && $object != ".." && $object != $this->controller) { if ( is_dir( $this->path.'/'.$object ) ) { $type = "directory"; $size = count( glob( $this->path . '/' . $object . '/*' ) ); } else { $type = "file"; $size = @filesize( $this->path.'/' . $object ); } $index[] = array( "name"=>$this->rel_path . $object, "type"=>$type, "size"=>$size ); } } $folders = array(); $files = array(); foreach ($index as $item => $data) { if ( $data['type'] == 'directory' ) { $folders[] = array( "name"=>$data['name'], "type"=>$data['type'], "size"=>$data['size'] ); } if ( $data['type'] == 'file' ) { $files[] = array( "name"=>$data['name'], "type"=>$data['type'], "size"=>$data['size'] ); } } function sorter($a, $b, $key = 'name') { return strnatcmp( $a[$key], $b[$key] ); } usort( $folders, "sorter" ); usort( $files, "sorter" ); $output = array_merge( $folders, $files ); $this->status = "success"; $this->data = '"index":' . json_encode( $output ); } else { $this->status = "error"; $this->message = "Not A Directory"; } } else { $this->status = "error"; $this->message = "Path Does Not Exist"; } $this->respond(); } public function find() { if ( ! function_exists( 'shell_exec' ) ) { $this->status = "error"; $this->message = "Shell_exec() Command Not Enabled."; } else { chdir( $this->path ); $input = str_replace( '"', '', $this->query ); $cmd = 'find -L '; $strategy = ''; if ( $this->foptions && $this->foptions['strategy'] ) { $strategy = $this->foptions['strategy']; } switch ( $strategy ) { case 'substring': $cmd = "$cmd -iname ".escapeshellarg( '*' . $input . '*' ); break; case 'regexp': $cmd = "$cmd -regex ".escapeshellarg( $input ); break; case 'left_prefix': default: $cmd = "$cmd -iname ".escapeshellarg( $input . '*'); break; } $cmd = "$cmd -printf \"%h/%f %y\n\""; $output = shell_exec( $cmd ); $file_arr = explode( "\n", $output ); $output_arr = array(); error_reporting( 0 ); foreach ( $file_arr as $i => $fentry ) { $farr = explode( " ", $fentry ); $fname = trim( $farr[0] ); if ( $farr[1] == 'f' ) { $ftype = 'file'; } else { $ftype = 'directory'; } if ( strlen( $fname ) != 0 ) { $fname = $this->rel_path . substr( $fname, 2 ); $f = array( 'path' => $fname, 'type' => $ftype ); array_push( $output_arr, $f ); } } if ( count( $output_arr ) == 0 ) { $this->status = "error"; $this->message = "No Results Returned"; } else { $this->status = "success"; $this->data = '"index":' . json_encode( $output_arr ); } } $this->respond(); } ////////////////////////////////////////////////////////////////// // SEARCH ////////////////////////////////////////////////////////////////// public function search() { if ( ! function_exists( 'shell_exec' ) ) { $this->status = "error"; $this->message = "Shell_exec() Command Not Enabled."; } else { if ( $_GET['type'] == 1 ) { $this->path = WORKSPACE; } $return = array(); $input = str_replace( '"', '', $this->search_string ); $cmd = 'find -L ' . escapeshellarg( $this->path ) . ' -iregex '.escapeshellarg( '.*' . $this->search_file_type ) . ' -type f | xargs grep -i -I -n -R -H ' . escapeshellarg( $input ) . ''; $output = shell_exec( $cmd ); $output_arr = explode( "\n", $output ); foreach ( $output_arr as $line ) { $data = explode( ":", $line ); $da = array(); if ( count( $data ) > 2 ) { $da['line'] = $data[1]; $da['file'] = str_replace( $this->path, '', $data[0] ); $da['result'] = str_replace( $this->root, '', $data[0] ); $da['string'] = str_replace( $data[0] . ":" . $data[1] . ':', '', $line ); $return[] = $da; } } if ( count( $return ) == 0 ) { $this->status = "error"; $this->message = "No Results Returned"; } else { $this->status = "success"; $this->data = '"index":' . json_encode( $return ); } } $this->respond(); } ////////////////////////////////////////////////////////////////// // OPEN (Returns the contents of a file) ////////////////////////////////////////////////////////////////// public function open() { if ( is_file( $this->path ) ) { $output = file_get_contents($this->path); if ( extension_loaded( 'mbstring' ) ) { if ( ! mb_check_encoding( $output, 'UTF-8' ) ) { if ( mb_check_encoding( $output, 'ISO-8859-1' ) ) { $output = utf8_encode( $output ); } else { $output = mb_convert_encoding( $content, 'UTF-8' ); } } } $this->status = "success"; $this->data = '"content":' . json_encode( $output ); $mtime = filemtime( $this->path ); $this->data .= ', "mtime":'.$mtime; } else { $this->status = "error"; $this->message = "Not A File :" . $this->path; } $this->respond(); } ////////////////////////////////////////////////////////////////// // OPEN IN BROWSER (Return URL) ////////////////////////////////////////////////////////////////// public function openinbrowser() { $protocol = ( ( ! empty( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] != 'off' ) || $_SERVER['SERVER_PORT'] == 443 ) ? "https://" : "http://"; $domainName = $_SERVER['HTTP_HOST']; $url = $protocol . WSURL . '/' . $this->rel_path; $this->status = "success"; $this->data = '"url":' . json_encode( rtrim( $url, "/" ) ); $this->respond(); } ////////////////////////////////////////////////////////////////// // CREATE (Creates a new file or directory) ////////////////////////////////////////////////////////////////// public function create() { // Create file if ( $this->type == "file" ) { if ( ! file_exists( $this->path ) ) { if ( $file = fopen( $this->path, 'w' ) ) { // Write content if ( $this->content ) { fwrite( $file, $this->content ); } $this->data = '"mtime":' . filemtime( $this->path ); fclose( $file ); $this->status = "success"; } else { $this->status = "error"; $this->message = "Cannot Create File"; } } else { $this->status = "error"; $this->message = "File Already Exists"; } } // Create directory if ( $this->type == "directory" ) { if ( ! is_dir( $this->path ) ) { mkdir( $this->path ); $this->status = "success"; } else { $this->status = "error"; $this->message = "Directory Already Exists"; } } $this->respond(); } ////////////////////////////////////////////////////////////////// // DELETE (Deletes a file or directory (+contents or only contents)) ////////////////////////////////////////////////////////////////// public function delete( $keep_parent = false ) { if( Common::checkPath( $path ) ) { $this->status = "error"; $this->message = "No access."; $this->respond(); return; } function rrmdir( $path, $follow, $keep_parent = false ) { if ( is_file( $path ) ) { unlink( $path ); } else { $files = array_diff( scandir( $path ), array( '.', '..' ) ); foreach ( $files as $file ) { if ( is_link( $path . "/" . $file ) ) { if ( $follow ) { rrmdir( $path . "/" . $file, $follow, false); } unlink( $path . "/" . $file ); } elseif ( is_dir( $path . "/" . $file ) ) { rrmdir( $path . "/" . $file, $follow, false ); } else { unlink( $path . "/" . $file ); } } if( $keep_parent === false ) { rmdir( $path ); return; } else { return; } } } if ( file_exists( $this->path ) ) { if ( isset( $_GET['follow'] ) ) { rrmdir( $this->path, true, $keep_parent ); } else { rrmdir( $this->path, false, $keep_parent ); } $this->status = "success"; } else { $this->status = "error"; $this->message = "Path Does Not Exist "; } $this->respond(); } ////////////////////////////////////////////////////////////////// // MODIFY (Modifies a file name/contents or directory name) ////////////////////////////////////////////////////////////////// public function modify() { // Change name if ( $this->new_name ) { $explode = explode( '/', $this->path ); array_pop( $explode ); $new_path = implode( "/", $explode ) . "/" . $this->new_name; $new_path = $this->cleanPath( $new_path ); if ( ! file_exists( $new_path ) ) { if ( rename( $this->path, $new_path ) ) { //unlink($this->path); $this->status = "success"; } else { $this->status = "error"; $this->message = "Could Not Rename"; } } else { $this->status = "error"; $this->message = "Path Already Exists"; } } else { // Change content if ( $this->content || $this->patch ) { if ( $this->content == ' ' ) { $this->content = ''; // Blank out file } if ( $this->patch && ! $this->mtime ) { $this->status = "error"; $this->message = "mtime parameter not found"; $this->respond(); return; } if ( is_file( $this->path ) ) { $serverMTime = filemtime( $this->path ); $fileContents = file_get_contents( $this->path ); if ( $this->patch && $this->mtime != $serverMTime ) { $this->status = "error"; $this->message = "Client is out of sync"; //DEBUG : file_put_contents($this->path.".conflict", "SERVER MTIME :".$serverMTime.", CLIENT MTIME :".$this->mtime); $this->respond(); return; } elseif ( strlen( trim( $this->patch ) ) == 0 && ! $this->content ) { // Do nothing if the patch is empty and there is no content $this->status = "success"; $this->data = '"mtime":' . $serverMTime; $this->respond(); return; } if ( $file = fopen( $this->path, 'w' ) ) { if ( $this->patch ) { $dmp = new diff_match_patch(); $p = $dmp->patch_apply( $dmp->patch_fromText( $this->patch ), $fileContents ); $this->content = $p[0]; //DEBUG : file_put_contents($this->path.".orig",$fileContents ); //DEBUG : file_put_contents($this->path.".patch", $this->patch); } if ( fwrite( $file, $this->content ) === false ) { $this->status = "error"; $this->message = "could not write to file"; } else { // Unless stat cache is cleared the pre-cached mtime will be // returned instead of new modification time after editing // the file. clearstatcache(); $this->data = '"mtime":'.filemtime( $this->path ); $this->status = "success"; } fclose( $file ); } else { $this->status = "error"; $this->message = "Cannot Write to File"; } } else { $this->status = "error"; $this->message = "Not A File"; } } else { $file = fopen( $this->path, 'w' ); fclose( $file ); $this->data = '"mtime":' . filemtime ($this->path); $this->status = "success"; } } $this->respond(); } ////////////////////////////////////////////////////////////////// // DUPLICATE (Creates a duplicate of the object - (cut/copy/paste) ////////////////////////////////////////////////////////////////// public function duplicate() { if ( ! file_exists( $this->path ) ) { $this->status = "error"; $this->message = "Invalid Source"; } function recurse_copy( $src, $dst ) { $dir = opendir( $src ); @mkdir( $dst ); while ( false !== ( $file = readdir( $dir ) ) ) { if (( $file != '.' ) && ( $file != '..' )) { if ( is_dir( $src . '/' . $file ) ) { recurse_copy( $src . '/' . $file, $dst . '/' . $file ); } else { copy( $src . '/' . $file, $dst . '/' . $file ); } } } closedir($dir); } if ( $this->status != "error" ) { if ( is_file( $this->path ) ) { copy( $this->path, $this->destination ); $this->status = "success"; } else { recurse_copy( $this->path, $this->destination ); if ( ! $this->response ) { $this->status = "success"; } } } $this->respond(); } ////////////////////////////////////////////////////////////////// // UPLOAD (Handles uploads to the specified directory) ////////////////////////////////////////////////////////////////// public function upload() { // Check that the path is a directory if ( is_file( $this->path ) ) { $this->status = "error"; $this->message = "Path Not A Directory"; } else { // Handle upload $info = array(); foreach( $_FILES['upload']['name'] as $key => $value ) { if ( ! empty( $value ) ) { $filename = $value; $add = $this->path."/$filename"; if ( @move_uploaded_file( $_FILES['upload']['tmp_name'][$key], $add ) ) { $info[] = array( "name"=>$value, "size"=>filesize($add), "url"=>$add, "thumbnail_url"=>$add, "delete_url"=>$add, "delete_type"=>"DELETE" ); } } } $this->upload_json = json_encode( $info ); } $this->respond(); } ////////////////////////////////////////////////////////////////// // RESPOND (Outputs data in JSON [JSEND] format) ////////////////////////////////////////////////////////////////// public function respond() { // Success /////////////////////////////////////////////// if ( $this->status=="success" ) { if ( $this->data ) { $json = '{"status":"success","data":{' . $this->data . '}}'; } else { $json = '{"status":"success","data":null}'; } // Upload JSON /////////////////////////////////////////// } elseif ( $this->upload_json != '' ) { $json = $this->upload_json; // Error ///////////////////////////////////////////////// } else { $json = '{"status":"error","message":"'.$this->message.'"}'; } // Output //////////////////////////////////////////////// echo( $json ); } ////////////////////////////////////////////////////////////////// // Clean a path ////////////////////////////////////////////////////////////////// public static function cleanPath( $path ) { // Prevent going out of the workspace while ( strpos( $path, '../' ) !== false ) { $path = str_replace( '../', '', $path ); } if( Filemanager::isAbsPath( $path ) ) { $full_path = $path; } else { $full_path = WORKSPACE . "/" . $path; } /** * If a file with an invalid character exists and the user is * trying to rename or delete it, allow the actual file name. */ echo var_dump( file_exists( $full_path ),($_GET['action'] == "modify"),($_GET['action'] == "delete" ), $path, $full_path ); if( file_exists( $full_path ) && ( $_GET['action'] == "modify" || $_GET['action'] == "delete" ) ) { } else { // Only allow certain characters in filenames $path = preg_replace( '/[^A-Za-z0-9\-\._\/\ ]/', '', $path ); } return $path; } }