File manager - Edit - /home/theblueo/tv/fb4e3b/ajax.tar
Back
FsConnectController.php 0000666 00000013364 15214044167 0011222 0 ustar 00 <?php /** * Ajax service that provides remote server authentication for file system *write* operations */ class Loco_ajax_FsConnectController extends Loco_mvc_AjaxController { /** * @var Loco_api_WordPressFileSystem */ private $api; /** * @param Loco_fs_File existing file path (must exist) * @return bool */ private function authorizeDelete( Loco_fs_File $file ){ $files = new Loco_fs_Siblings($file); // require remote authentication if at least one dependant file is not deletable directly foreach( $files->expand() as $file ){ if( ! $this->api->authorizeDelete($file) ){ return false; } } // else no dependants failed deletable test return true; } /** * @param Loco_fs_File file being moved (must exist) * @param Loco_fs_File target path (should not exist) * @return bool */ private function authorizeMove( Loco_fs_File $source, Loco_fs_File $target = null ){ return $this->api->authorizeMove($source,$target); } /** * @param Loco_fs_File new file path (should not exist) * @return bool */ private function authorizeCreate( Loco_fs_File $file ){ return $this->api->authorizeCreate($file); } /** * @return bool */ private function authorizeUpdate( Loco_fs_File $file ){ if( ! $this->api->authorizeUpdate($file) ){ return false; } // if backups are enabled, we need to be able to create new files too (i.e. update parent directory) if( Loco_data_Settings::get()->num_backups && ! $this->api->authorizeCopy($file) ){ return false; } // updating file may also recompile binary, which may or may not exist $files = new Loco_fs_Siblings( $file ); if( $file = $files->getBinary() ){ return $this->api->authorizeSave($file); } // else no dependants to update return true; } /** * {@inheritdoc} */ public function render(){ // establish operation being authorized (create,delete,etc..) $post = $this->validate(); $type = $post->auth; $func = 'authorize'.ucfirst($type); $auth = array( $this, $func ); if( ! is_callable($auth) ){ throw new Loco_error_Exception('Unexpected file operation'); } // all auth methods require at least one file argument $file = new Loco_fs_File( $post->path ); $base = loco_constant('WP_CONTENT_DIR'); $file->normalize($base); $args = array($file); // some auth methods also require a destination/target (move,copy,etc..) if( $dest = $post->dest ){ $file = new Loco_fs_File($dest); $file->normalize($base); $args[] = $file; } // call auth method and respond with status and prompt HTML if connect required try { $this->api = new Loco_api_WordPressFileSystem; if( call_user_func_array($auth,$args) ){ $this->set( 'authed', true ); $this->set( 'valid', $this->api->getOutputCredentials() ); $this->set( 'creds', $this->api->getInputCredentials() ); $this->set( 'method', $this->api->getFileSystem()->method ); $this->set( 'success', __('Connected to remote file system','loco-translate') ); // warning when writing to this location is risky (overwrites during wp update) if( Loco_data_Settings::get()->fs_protect && $file->getUpdateType() ){ if( 'create' === $type ){ $message = __('This file may be overwritten or deleted when you update WordPress','loco-translate'); } else if( 'delete' === $type ){ $message = __('This directory is managed by WordPress, be careful what you delete','loco-translate'); } else if( 'move' === $type ){ $message = __('This directory is managed by WordPress. Removed files may be restored during updates','loco-translate'); } else { $message = __('Changes to this file may be overwritten or deleted when you update WordPress','loco-translate'); } $this->set('warning',$message); } } else if( $html = $this->api->getForm() ){ $this->set( 'authed', false ); $this->set( 'prompt', $html ); // supporting text based on file operation type explains why auth is required if( 'create' === $type ){ $message = __('Creating this file requires permission','loco-translate'); } else if( 'delete' === $type ){ $message = __('Deleting this file requires permission','loco-translate'); } else if( 'move' === $type ){ $message = __('This move operation requires permission','loco-translate'); } else { $message = __('Saving this file requires permission','loco-translate'); } // message is printed before default text, so needs delimiting. $this->set('message',$message.'.'); } else { throw new Loco_error_Exception('Failed to get credentials form'); } } catch( Loco_error_WriteException $e ){ $this->set('authed', false ); $this->set('reason', $e->getMessage() ); } return parent::render(); } } DiffController.php 0000666 00000003572 15214044167 0010210 0 ustar 00 <?php /** * Ajax "diff" route, for rendering PO/POT file diffs */ class Loco_ajax_DiffController extends Loco_mvc_AjaxController { /** * {@inheritdoc} */ public function render(){ $post = $this->validate(); // require x2 valid files for diffing if( ! $post->lhs || ! $post->rhs ){ throw new InvalidArgumentException('Path parameters required'); } $dir = loco_constant('WP_CONTENT_DIR'); $lhs = new Loco_fs_File( $post->lhs ); $lhs->normalize($dir); $rhs = new Loco_fs_File( $post->rhs ); $rhs->normalize($dir); // avoid diffing non Gettext source files $exts = array_flip( array( 'pot', 'pot~', 'po', 'po~' ) ); /* @var $file Loco_fs_File */ foreach( array($lhs,$rhs) as $file ){ if( ! $file->exists() ){ throw new InvalidArgumentException('File paths must exist'); } if( ! $file->underContentDirectory() ){ throw new InvalidArgumentException('Files must be under '.basename($dir) ); } $ext = $file->extension(); if( ! isset($exts[$ext]) ){ throw new InvalidArgumentException('Disallowed file extension'); } } // OK to diff files as HTML table $renderer = new Loco_output_DiffRenderer; $emptysrc = $renderer->_startDiff().$renderer->_endDiff(); $tablesrc = $renderer->renderFiles( $rhs, $lhs ); if( $tablesrc === $emptysrc ){ // translators: Where %s is a file name $message = __('Revisions are identical, you can delete %s','loco-translate'); $this->set( 'error', sprintf( $message, $rhs->basename() ) ); } else { $this->set( 'html', $tablesrc ); } return parent::render(); } } SyncController.php 0000666 00000006211 15214044167 0010245 0 ustar 00 <?php /** * Ajax "sync" route. * Performs the basic in-editor sync function from the old 1.x version. */ class Loco_ajax_SyncController extends Loco_mvc_AjaxController { /** * {@inheritdoc} */ public function render(){ $post = $this->validate(); $bundle = Loco_package_Bundle::fromId( $post->bundle ); $project = $bundle->getProjectById( $post->domain ); if( ! $project instanceof Loco_package_Project ){ throw new Loco_error_Exception('No such project '.$post->domain); } $file = new Loco_fs_File( $post->path ); $base = loco_constant('WP_CONTENT_DIR'); $file->normalize( $base ); // POT file always synced with source code (even if a PO being used as POT) if( 'pot' === $post->type ){ $potfile = null; } // allow post data to force a template file path else if( $path = $post->sync ){ $potfile = new Loco_fs_File($path); $potfile->normalize( $base ); } // else use project-configured template if one is defined else { $potfile = $project->getPot(); } // sync with POT if it exists if( $potfile && $potfile->exists() ){ $this->set('pot', $potfile->basename() ); try { $data = Loco_gettext_Data::load($potfile); } catch( Exception $e ){ // translators: Where %s is the name of the invalid POT file throw new Loco_error_ParseException( sprintf( __('Translation template is invalid (%s)','loco-translate'), $potfile->basename() ) ); } } // else sync with source code else { $this->set('pot', '' ); $domain = (string) $project->getDomain(); $extr = new Loco_gettext_Extraction($bundle); $extr->addProject($project); // bail if any files were skipped if( $list = $extr->getSkipped() ){ $n = count($list); $maximum = Loco_mvc_FileParams::renderBytes( wp_convert_hr_to_bytes( Loco_data_Settings::get()->max_php_size ) ); $largest = Loco_mvc_FileParams::renderBytes( $extr->getMaxPhpSize() ); // Translators: Where %2$s is the maximum size of a file that will be included and %3$s is the largest encountered $text = _n('One file has been skipped because it\'s %3$s. (Max is %2$s). Check all strings are present before saving.','%s files over %2$s have been skipped. (Largest is %3$s). Check all strings are present before saving.',$n,'loco-translate'); $text = sprintf( $text, number_format($n), $maximum, $largest ); // not failing, just warning. Nothing will be saved until user saves editor state Loco_error_AdminNotices::warn( $text ); } // OK to return available strings $data = $extr->includeMeta()->getTemplate($domain); } $this->set( 'po', $data->jsonSerialize() ); return parent::render(); } } DownloadConfController.php 0000666 00000001661 15214044167 0011712 0 ustar 00 <?php /** * Downloads a bundle configuration as XML or Json */ class Loco_ajax_DownloadConfController extends Loco_ajax_common_BundleController { /** * {@inheritdoc} */ public function render(){ $this->validate(); $bundle = $this->getBundle(); $file = new Loco_fs_File( $this->get('path') ); // TODO should we download axtual loco.xml file if bundle is configured from it? //$file->normalize( $bundle->getDirectoryPath() ); //if( $file->exists() ){} $writer = new Loco_config_BundleWriter($bundle); switch( $file->extension() ){ case 'xml': return $writer->toXml(); case 'json': return json_encode( $writer->jsonSerialize() ); } // @codeCoverageIgnoreStart throw new Loco_error_Exception('Specify either XML or JSON file path'); } } MsginitController.php 0000666 00000011701 15214044167 0010743 0 ustar 00 <?php /** * Ajax "msginit" route, for initializing new translation files */ class Loco_ajax_MsginitController extends Loco_ajax_common_BundleController { /** * @return Loco_Locale */ private function getLocale(){ if( $this->get('use-selector') ){ $tag = $this->get('select-locale'); } else { $tag = $this->get('custom-locale'); } $locale = Loco_Locale::parse($tag); if( ! $locale->isValid() ){ throw new Loco_error_LocaleException('Invalid locale'); } return $locale; } /** * {@inheritdoc} */ public function render(){ $post = $this->validate(); $bundle = $this->getBundle(); $project = $this->getProject( $bundle ); $domain = (string) $project->getDomain(); $locale = $this->getLocale(); $suffix = (string) $locale; // The front end posts a template path, so we must replace the actual locale code $base = loco_constant('WP_CONTENT_DIR'); $path = $post->path[ $post['select-path'] ]; // The request_filesystem_credentials function will try to access the "path" field later $_POST['path'] = $path; $pofile = new Loco_fs_LocaleFile( $path ); if( $suffix !== $pofile->getSuffix() ){ $pofile = $pofile->cloneLocale( $locale ); if( $suffix !== $pofile->getSuffix() ){ throw new Loco_error_Exception('Failed to suffix file path with locale code'); } } // target PO should not exist yet $pofile->normalize( $base ); $api = new Loco_api_WordPressFileSystem; $api->authorizeCreate( $pofile ); // Target MO probably doesn't exist, but we don't want to overwrite it without asking $mofile = $pofile->cloneExtension('mo'); if( $mofile->exists() ){ throw new Loco_error_Exception( __('MO file exists for this language already. Delete it first','loco-translate') ); } /*/ Same for JSON file, but WordPress >= only 5 $jsfile = function_exists('wp_set_script_translations') ? $pofile->cloneExtension('json') : null; if( $jsfile && $jsfile->exists() ){ throw new Loco_error_Exception( __('JSON file exists for this language already. Delete it first','loco-translate') ); }*/ // Permit forcing of any parsable file as strings template if( $source = $post->source ){ $potfile = new Loco_fs_File( $source ); $potfile->normalize( $base ); $data = Loco_gettext_Data::load($potfile); // Remove target strings when copying PO if( $post->strip ){ $data->strip(); } } // else parse POT file if project defines one that exists else if( ( $potfile = $project->getPot() ) && $potfile->exists() ){ $data = Loco_gettext_Data::load($potfile); } // else extract directly from source code, assuming domain passed though from front end else { $extr = new Loco_gettext_Extraction( $bundle ); $data = $extr->addProject($project)->includeMeta()->getTemplate($domain); $potfile = null; } // Let template define Project-Id-Version, else set header to current project name $headers = array(); $vers = $data->getHeaders()->{'Project-Id-Version'}; if( ! $vers || 'PACKAGE VERSION' === $vers ){ $headers['Project-Id-Version'] = $project->getName(); } // relative path from bundle root to the template/source this file was created from if( $potfile && $post->link ){ $headers['X-Loco-Template'] = $potfile->getRelativePath( $bundle->getDirectoryPath() ); } $data->localize( $locale, $headers ); $posize = $pofile->putContents( $data->msgcat() ); $mosize = $mofile->putContents( $data->msgfmt() ); //$jssize = $jsfile && ( $sub = $data->splitJs() ) ? $jsfile->putContents($data->jedize($domain,$sub)) : 0; // set debug response data $this->set( 'debug', array ( 'poname' => $pofile->basename(), 'posize' => $posize, 'mosize' => $mosize, //'jssize' => $jssize, 'source' => $potfile ? $potfile->basename() : '', ) ); // push recent items on file creation // TODO push project and locale file Loco_data_RecentItems::get()->pushBundle( $bundle )->persist(); // front end will redirect to the editor $type = strtolower( $this->get('type') ); $this->set( 'redirect', Loco_mvc_AdminRouter::generate( sprintf('%s-file-edit',$type), array ( 'path' => $pofile->getRelativePath($base), 'bundle' => $bundle->getHandle(), 'domain' => $project->getId(), ) ) ); return parent::render(); } } DownloadController.php 0000666 00000003642 15214044167 0011105 0 ustar 00 <?php /** * Ajax "download" route, for outputting raw gettext file contents. */ class Loco_ajax_DownloadController extends Loco_mvc_AjaxController { /** * {@inheritdoc} */ public function render(){ $post = $this->validate(); // we need a path, but it may not need to exist $file = new Loco_fs_File( $this->get('path') ); $file->normalize( loco_constant( 'WP_CONTENT_DIR') ); $is_binary = 'mo' === strtolower( $file->extension() ); // posted source must be clean and must parse as whatever the file extension claims to be if( $raw = $post->source ){ // compile source if target is MO if( $is_binary ) { $raw = Loco_gettext_Data::fromSource($raw)->msgfmt(); } } // else file can be output directly if it exists. // note that files on disk will not be parsed or manipulated. they will download strictly as-is else if( $file->exists() ){ $raw = $file->getContents(); } /*/ else if PO exists but MO doesn't, we can compile it on the fly else if( ! $is_binary ){ }*/ else { throw new Loco_error_Exception('File not found and no source posted'); } // Observe UTF-8 BOM setting if( ! $is_binary ){ $has_bom = "\xEF\xBB\xBF" === substr($raw,0,3); $use_bom = (bool) Loco_data_Settings::get()->po_utf8_bom; // only alter file if valid UTF-8. Deferring detection overhead until required if( $has_bom !== $use_bom && 'UTF-8' === mb_detect_encoding( $raw, array('UTF-8','ISO-8859-1'), true ) ){ if( $use_bom ){ $raw = "\xEF\xBB\xBF".$raw; // prepend } else { $raw = substr($raw,3); // strip bom } } } return $raw; } } SaveController.php 0000666 00000015334 15214044167 0010235 0 ustar 00 <?php /** * Ajax "save" route, for saving editor contents to disk */ class Loco_ajax_SaveController extends Loco_ajax_common_BundleController { /** * {@inheritdoc} */ public function render(){ $post = $this->validate(); // path parameter must not be empty $path = $post->path; if( ! $path ){ throw new InvalidArgumentException('Path parameter required'); } // locale must be posted to indicate whether PO or POT $locale = $post->locale; if( is_null($locale) ){ throw new InvalidArgumentException('Locale parameter required'); } $pofile = new Loco_fs_LocaleFile( $path ); $pofile->normalize( loco_constant('WP_CONTENT_DIR') ); $poexists = $pofile->exists(); // ensure we only deal with PO/POT source files. // posting of MO file paths is permitted when PO is missing, but we're about to fix that $ext = $pofile->extension(); if( 'mo' === $ext ){ $pofile = $pofile->cloneExtension('po'); } else if( 'pot' === $ext ){ $locale = ''; } else if( 'po' !== $ext ){ throw new Loco_error_Exception('Invalid file path'); } // force the use of remote file system when configured from front end $api = new Loco_api_WordPressFileSystem; // data posted may be either 'multipart/form-data' (recommended for large files) if( isset($_FILES['po']) ){ $data = Loco_gettext_Data::fromSource( Loco_data_Upload::src('po') ); } // else 'application/x-www-form-urlencoded' by default else { $data = Loco_gettext_Data::fromSource( $post->data ); } // WordPress-ize some headers that differ from JavaScript libs if( $compile = (bool) $locale ){ $head = $data->getHeaders(); $head['Language'] = strtr( $locale, '-', '_' ); } // backup existing file before overwriting, but still allow if backups fails $num_backups = Loco_data_Settings::get()->num_backups; if( $num_backups && $poexists ){ try { $api->authorizeCopy( $pofile ); $backups = new Loco_fs_Revisions( $pofile ); $backups->create(); $backups->prune($num_backups); } catch( Exception $e ){ Loco_error_AdminNotices::debug( $e->getMessage() ); $message = __('Failed to create backup file in "%s". Check file permissions or disable backups','loco-translate'); Loco_error_AdminNotices::warn( sprintf( $message, $pofile->getParent()->basename() ) ); } } // commit file directly to disk $api->authorizeSave( $pofile ); $bytes = $pofile->putContents( $data->msgcat() ); $mtime = $pofile->modified(); // add bundle to recent items on file creation try { $bundle = $this->getBundle(); Loco_data_RecentItems::get()->pushBundle( $bundle )->persist(); } catch( Exception $e ){ // editor permitted to save files not in a bundle, so catching failures $bundle = null; } // start success data with bytes written and timestamp $this->set('locale', $locale ); $this->set('pobytes', $bytes ); $this->set('poname', $pofile->basename() ); $this->set('modified', $mtime); $this->set('datetime', Loco_mvc_ViewParams::date_i18n($mtime) ); // Compile MO and JSON files unless saving template if( $compile ){ try { $mofile = $pofile->cloneExtension('mo'); $api->authorizeSave( $mofile ); $bytes = $mofile->putContents( $data->msgfmt() ); $this->set( 'mobytes', $bytes ); Loco_error_AdminNotices::success( __('PO file saved and MO file compiled','loco-translate') ); } catch( Exception $e ){ Loco_error_AdminNotices::debug( $e->getMessage() ); Loco_error_AdminNotices::warn( __('PO file saved, but MO file compilation failed','loco-translate') ); $this->set( 'mobytes', 0 ); // prevent further compilation if MO failed $compile = false; } } else { Loco_error_AdminNotices::success( __('POT file saved','loco-translate') ); } /*/ Compile JSON translations for WordPress >= 5 if( $compile && $bundle && function_exists('wp_set_script_translations') ){ $bytes = 0; try { list($domain) = Loco_package_Project::splitId( $this->get('domain') ); // hash file reference according to WordPress logic (see load_script_textdomain) $base = $pofile->dirname().'/'.$pofile->filename(); foreach( $data->exportRefs('\\.jsx?') as $ref => $messages ){ if( '.min.js' === substr($ref,-7) ) { $ref = substr($ref,0,-7).'.js'; } // filter similarly to WP's `load_script_textdomain_relative_path` which is called from `load_script_textdomain` $ref = apply_filters( 'loco_script_relative_path', $ref, $domain ); // referenced file must exist in bundle, or will never be loaded and so not require a .json file $file = new Loco_fs_File( $bundle->getDirectoryPath().'/'.$ref ); if( $file->exists() && ! $file->isDirectory() ){ $file = new Loco_fs_File( $base.'-'.md5($ref).'.json' ); $api->authorizeSave( $file ); $bytes += $file->putContents( $data->jedize($domain,$messages) ); } else { Loco_error_AdminNotices::warn( sprintf('%s not found in bundle',$ref) ); } } // single JSON file containing all .js ref from this file if( $messages = $data->splitJs() ){ $file = $pofile->cloneExtension('json'); $api->authorizeSave( $file ); $bytes = $file->putContents( $data->jedize($domain,$messages) ); } } catch( Exception $e ){ Loco_error_AdminNotices::debug( $e->getMessage() ); Loco_error_AdminNotices::warn( __('JSON compilation failed','loco-translate') ); } $this->set( 'jsbytes', $bytes ); }*/ return parent::render(); } } XgettextController.php 0000666 00000005532 15214044167 0011152 0 ustar 00 <?php /** * Ajax "xgettext" route, for initializing new template file from source code */ class Loco_ajax_XgettextController extends Loco_ajax_common_BundleController { /** * {@inheritdoc} */ public function render(){ $this->validate(); $bundle = $this->getBundle(); $project = $this->getProject( $bundle ); // target location may not be next to POT file at all $base = loco_constant('WP_CONTENT_DIR'); $target = new Loco_fs_Directory( $this->get('path') ); $target->normalize( $base ); if( $target->exists() && ! $target->isDirectory() ){ throw new Loco_error_Exception('Target is not a directory'); } // basename should be posted from front end $name = $this->get('name'); if( ! $name ){ throw new Loco_error_Exception('Front end did not post $name'); } // POT file shouldn't exist currently $potfile = new Loco_fs_File( $target.'/'.$name ); $api = new Loco_api_WordPressFileSystem; $api->authorizeCreate($potfile); // Do extraction and grab only given domain's strings $ext = new Loco_gettext_Extraction( $bundle ); $domain = $project->getDomain()->getName(); $data = $ext->addProject($project)->includeMeta()->getTemplate( $domain ); // additional headers to set in new POT file $head = $data->getHeaders(); $head['Project-Id-Version'] = $project->getName(); // write POT file to disk returning byte length $potsize = $potfile->putContents( $data->msgcat(true) ); // set response data for debugging if( loco_debugging() ){ $this->set( 'debug', array ( 'potname' => $potfile->basename(), 'potsize' => $potsize, 'total' => $ext->getTotal(), ) ); } // push recent items on file creation // TODO push project and locale file Loco_data_RecentItems::get()->pushBundle( $bundle )->persist(); // put flash message into session to be displayed on redirected page try { Loco_data_Session::get()->flash('success', __('Template file created','loco-translate') ); Loco_data_Session::close(); } catch( Exception $e ){ Loco_error_AdminNotices::debug( $e->getMessage() ); } // redirect front end to bundle view. Discourages manual editing of template $type = strtolower( $bundle->getType() ); $href = Loco_mvc_AdminRouter::generate( sprintf('%s-view',$type), array( 'bundle' => $bundle->getHandle(), ) ); $hash = '#loco-'.$project->getId(); $this->set( 'redirect', $href.$hash ); return parent::render(); } } common/BundleController.php 0000666 00000002235 15214044167 0012034 0 ustar 00 <?php /** * Common functions for all Ajax actions that operate on a bundle */ abstract class Loco_ajax_common_BundleController extends Loco_mvc_AjaxController { /** * @return Loco_package_Bundle */ protected function getBundle(){ if( $id = $this->get('bundle') ){ // type may be passed as separate argument if( $type = $this->get('type') ){ return Loco_package_Bundle::createType( $type, $id ); } // else embedded in standalone bundle identifier // TODO standardize this across all Ajax end points return Loco_package_Bundle::fromId($id); } // else may have type embedded in bundle throw new Loco_error_Exception('No bundle identifier posted'); } /** * @param Loco_package_Bundle * @return Loco_package_Project */ protected function getProject( Loco_package_Bundle $bundle ){ $project = $bundle->getProjectById( $this->get('domain') ); if( ! $project ){ throw new Loco_error_Exception('Failed to find translation project'); } return $project; } } FsReferenceController.php 0000666 00000017134 15214044167 0011526 0 ustar 00 <?php /** * Ajax service that returns source code for a given file system reference * Currently this is only PHP, but could theoretically be any file type. */ class Loco_ajax_FsReferenceController extends Loco_ajax_common_BundleController { /** * @param string * @return Loco_fs_File */ private function findSourceFile( $refpath ){ /*/ absolute file path means no search paths required if( Loco_fs_File::abs($refpath) ){ $srcfile = new Loco_fs_File( $refpath ); if( $srcfile->exists() ){ return $srcfile; } }*/ // reference may be resolvable via referencing PO file's location $pofile = new Loco_fs_File( $this->get('path') ); $pofile->normalize( loco_constant('WP_CONTENT_DIR') ); if( ! $pofile->exists() ){ throw new InvalidArgumentException('PO/POT file required to resolve reference'); } $search = new Loco_gettext_SearchPaths; $search->init($pofile); if( $srcfile = $search->match($refpath) ){ return $srcfile; } // check against PO file location when no search paths or search paths failed $srcfile = new Loco_fs_File($refpath); $srcfile->normalize( $pofile->dirname() ); if( $srcfile->exists() ){ return $srcfile; } // reference may be resolvable via known project roots try { $bundle = $this->getBundle(); // Loco extractions will always be relative to bundle root $srcfile = new Loco_fs_File( $refpath ); $srcfile->normalize( $bundle->getDirectoryPath() ); if( $srcfile->exists() ){ return $srcfile; } // check relative to parent theme root if( $bundle->isTheme() && ( $parent = $bundle->getParent() ) ){ $srcfile = new Loco_fs_File( $refpath ); $srcfile->normalize( $parent->getDirectoryPath() ); if( $srcfile->exists() ){ return $srcfile; } } // final attempt - search all project source roots // TODO is there too large a risk of false positives? especially with files like index.php /* @var $root Loco_fs_Directory */ /*foreach( $this->getProject($bundle)->getConfiguredSources() as $root ){ if( $root->isDirectory() ){ $srcfile = new Loco_fs_File( $refpath ); $srcfile->normalize( $root->getPath() ); if( $srcfile->exists() ){ return $srcfile; } } }*/ } catch( Loco_error_Exception $e ){ // permitted for there to be no bundle or project when viewing orphaned file } throw new Loco_error_Exception( sprintf('Failed to find source file matching "%s"',$refpath) ); } /** * {@inheritdoc} */ public function render(){ $post = $this->validate(); // at the very least we need a reference to examine if( ! $post->has('ref') ){ throw new InvalidArgumentException('ref parameter required'); } // reference must parse as <path>:<line> $ref = $post->ref; if( ! preg_match('/^(.+):(\\d+)$/', $ref, $r ) ){ throw new InvalidArgumentException('Invalid file reference, '.$ref ); } // find file or fail list( , $refpath, $refline ) = $r; $srcfile = $this->findSourceFile($refpath); // deny access to sensitive files if( 'wp-config.php' === $srcfile->basename() ){ throw new InvalidArgumentException('File access disallowed'); } // validate allowed source file types $conf = Loco_data_Settings::get(); $ext = strtolower( $srcfile->extension() ); $allow = array_merge( array('php','js'), $conf->php_alias, $conf->jsx_alias ); if( ! in_array($ext,$allow,true) ){ throw new InvalidArgumentException('File extension disallowed, '.$ext ); } // get file type from registered file extensions: $type = $conf->ext2type( $ext ); $this->set('type', $type ); $this->set('line', (int) $refline ); $this->set('path', $srcfile->getRelativePath( loco_constant('WP_CONTENT_DIR') ) ); // source code will be HTML-tokenized into multiple lines $code = array(); // observe the same size limits for source highlighting as for string extraction as tokenizing will use the same amount of juice $maxbytes = wp_convert_hr_to_bytes( $conf->max_php_size ); // tokenizers require gettext utilities, easiest just to ping the extraction library if( ! class_exists('Loco_gettext_Extraction',true) ){ throw new RuntimeException('Failed to load tokenizers'); // @codeCoverageIgnore } // PHP is the most likely format. if( 'php' === $type && ( $srcfile->size() <= $maxbytes ) && loco_check_extension('tokenizer') ) { $tokens = new LocoPHPTokens( token_get_all( $srcfile->getContents() ) ); } else if( 'js' === $type ){ $tokens = new LocoJsTokens( $srcfile->getContents() ); } else { $tokens = null; } // highlighting on back end because tokenizer provides more control than highlight.js if( $tokens instanceof LocoTokensInterface ){ $thisline = 1; while( $tok = $tokens->advance() ){ if( is_array($tok) ){ // line numbers added in PHP 5.2.2 - WordPress minimum is 5.2.4 list( $t, $str, $startline ) = $tok; $clss = token_name($t); // tokens can span multiple lines (whitespace/html/comments) $lines = preg_split('/\\R/', $str ); } else { // scalar symbol will always start on the line that the previous token ended on $clss = 'T_NONE'; $lines = array( $tok ); $startline = $thisline; } // token can span multiple lines, so include only bytes on required line[s] foreach( $lines as $i => $line ){ $thisline = $startline + $i; $html = '<code class="'.$clss.'">'.htmlentities($line,ENT_COMPAT,'UTF-8').'</code>'; // append highlighted token to current line $j = $thisline - 1; if( isset($code[$j]) ){ $code[$j] .= $html; } else { $code[$j] = $html; } } } } // permit limited other file types, but without back end highlighting else if( 'js' === $type || 'twig' === $type || 'php' === $type ){ foreach( preg_split( '/\\R/u', $srcfile->getContents() ) as $line ){ $code[] = '<code>'.htmlentities($line,ENT_COMPAT,'UTF-8').'</code>'; } } else { throw new Loco_error_Exception( sprintf('%s source view not supported', $type) ); // @codeCoverageIgnore } if( ! isset($code[$refline-1]) ){ throw new Loco_error_Exception( sprintf('Line %u not in source file', $refline) ); } $this->set( 'code', $code ); return parent::render(); } } PingController.php 0000666 00000001207 15214044167 0010226 0 ustar 00 <?php /** * Ajax "ping" route, for testing Ajax responses are working. */ class Loco_ajax_PingController extends Loco_mvc_AjaxController { /** * {@inheritdoc} */ public function render(){ $post = $this->validate(); // echo back bytes posted if( $post->has('echo') ){ $this->set( 'ping', $post['echo'] ); } // else just send pong else { $this->set( 'ping', 'pong' ); } // always send tick symbol to check json serializing of unicode $this->set( 'utf8', "\xE2\x9C\x93" ); return parent::render(); } }
| ver. 1.4 |
Github
|
.
| PHP 7.0.33 | Generation time: 0 |
proxy
|
phpinfo
|
Settings