Invision Power Services, Inc. * @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc. * @license http://www.invisionpower.com/legal/standards/ * @package IPS Social Suite * @since 12 Aug 2013 * @version SVN_VERSION_NUMBER */ namespace IPS\Output; /* To prevent PHP errors (extending class does not exist) revealing path */ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) { header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' ); exit; } /** * Javascript: Javascript handler */ class _Javascript extends \IPS\Patterns\ActiveRecord { /** * @brief [Javascript] Array of found javascript keys and objects */ protected static $foundJsObjects = array(); /** * @brief [Javascript] Position index for writing javascript to core_javascript */ protected static $positions = array(); /** * @brief [ActiveRecord] Multiton Store */ protected static $multitons; /** * @brief [ActiveRecord] Database Table */ public static $databaseTable = 'core_javascript'; /** * @brief [ActiveRecord] Database Prefix */ public static $databasePrefix = 'javascript_'; /** * @brief Javascript map of file object URLs */ protected static $javascriptObjects = null; /** * Find JavaScript file * * @param string $app Application key or Plugin key * @param string $location Location (front, admin, etc) * @param string $path Path * @param string $name Filename * @return \IPS\Output\Javascript * @throws \OutOfRangeException */ public static function find( $app, $location, $path, $name ) { $key = md5( $app . '-' . $location . '-' . $path . '-' . $name ); if ( !in_array( $key, static::$foundJsObjects ) ) { $where = array( 'javascript_app=?', 'javascript_location=?', 'javascript_path=?', 'javascript_name=?' ); if ( ! is_string( $app ) ) { $where[] = 'javascript_plugin=?'; $bindings = array( 'core', 'plugins', '/', $name, $app ); } else { $bindings = array( $app, $location, $path, $name ); } try { $js = \IPS\Db::i()->select( '*', 'core_javascript', array_merge( array( implode( ' AND ', $where ) ), $bindings ) )->first(); static::$foundJsObjects[ $key ] = parent::constructFromData( $js ); } catch ( \UnderflowException $e ) { throw new \OutOfRangeException; } } return static::$foundJsObjects[ $key ]; } /** * Set class properties if this object belongs to an application or a plugin * * @return void */ protected function setAppOrPluginProperties() { if ( ( $this->app AND ! is_string( $this->app ) ) OR ( $this->plugin ) ) { $this->app = 'core'; $this->location = 'plugins'; $this->path = '/'; $this->type = 'plugin'; $this->plugin = ( ! is_string( $this->app ) ) ? $this->app : $this->plugin; } } /** * Create a javascript file. This overwrites any existing JS that matches the same parameters. * If a $this->app is not a string, then it will assume plugin and automatically determine the correct 'app', 'location' and 'path' so these do not need to * be defined. * * @throws \InvalidArgumentException * @throws \RuntimeException * @return void */ public function save() { $this->setAppOrPluginProperties(); if ( ! isset( $this->path ) OR empty( $this->path ) ) { $this->path = '/'; } if ( ! $this->app OR ! $this->location OR ! $this->name ) { throw new \InvalidArgumentException; } if ( ! $this->type ) { $this->type = static::_getType( $this->path, $this->name ); } $key = ''; if ( \IPS\IN_DEV AND $this->type == 'plugin' ) { /* Write the file to disk in the correct location */ $path = \IPS\ROOT_PATH . '/plugins/' . $this->plugin . '/dev/js'; if ( !\is_dir( $path ) ) { if ( !@\mkdir( $path, 0777, true ) or !@\chmod( $path, 0777 ) ) { throw new \RuntimeException; } } $key = md5( $this->app . ';' . $this->location . ';' . $this->path . ';' . $this->name ); \file_put_contents( $path . '/' . $this->name, $this->content ); } \IPS\Db::i()->replace( 'core_javascript', array( 'javascript_app' => $this->app, 'javascript_location' => $this->location, 'javascript_plugin' => $this->plugin, 'javascript_path' => $this->path, 'javascript_name' => $this->name, 'javascript_type' => $this->type, 'javascript_content' => $this->content, 'javascript_version' => $this->version, 'javascript_position' => ( $this->position ) ? $this->position : 2000000, 'javascript_key' => $key ), array( 'javascript_app', 'javascript_location', 'javascript_path', 'javascript_name' ) ); } /** * Delete a javascript file * be defined. * * @throws \InvalidArgumentException * @return void */ public function delete() { $this->setAppOrPluginProperties(); if ( ! isset( $this->path ) OR empty( $this->path ) ) { $this->path = '/'; } if ( ! $this->app OR ! $this->location OR ! $this->name ) { throw new \InvalidArgumentException; } if ( ! $this->type ) { $this->type = static::_getType( $this->path, $this->name ); } if ( \IPS\IN_DEV AND $this->location == 'plugins' ) { /* Write the file to disk in the correct location */ $file = \IPS\ROOT_PATH . '/plugins/' . $this->plugin . '/dev/js/' . $this->name; if ( \is_file( $file ) ) { \unlink( $file ); } } $where = array( 'javascript_app=?', 'javascript_location=?', 'javascript_path=?', 'javascript_name=?' ); $bindings = array( $this->app, $this->location, $this->path, $this->name ); if ( $this->location == 'plugins' ) { $where[] = 'javascript_plugin=?'; $bindings[] = $this->plugin; } \IPS\Db::i()->delete( 'core_javascript', array( implode( ' AND ', $where ), $bindings ) ); } /** * Create an XML document * * @param string $app Application * @return XML Object */ public static function createXml( $app ) { static::importDev($app); if ( $app === 'core' ) { static::importDev('global'); } /* Build XML and write to app directory */ $xml = new \XMLWriter; $xml->openMemory(); $xml->setIndent( TRUE ); $xml->startDocument( '1.0', 'UTF-8' ); /* Root tag */ $xml->startElement('javascript'); $xml->startAttribute('app'); $xml->text( $app ); $xml->endAttribute(); /* Loop */ foreach ( \IPS\Db::i()->select( '*', 'core_javascript', ( $app === 'core' ) ? \IPS\Db::i()->in( 'javascript_app', array('core', 'global') ) : array( 'javascript_app=?', $app ), 'javascript_path, javascript_name' ) as $js ) { /* Initiate the