最近更新: 2008-02-21

Extend core libraries of CodeIgniter to detect the request file type and load applicable view

I extend core libraries of CodeIgniter to detect the request file type and load applicable view. The other way is use URI Route, see '文件格式之 URI Route Rule 與 CodeIgniter 之實作示範'.

What I want to do is that if user request 'http://localhost/ci/blogs/index.xml', it will try to load a view for XML. In other cases:

  • If request 'blogs/index', load 'views/index.php' to render HTML document (default type).
  • If request 'blogs/index.xml', load 'views/index.xml.php' to render XML document.
  • If request 'blogs/index.pdf', load 'views/index.pdf.php' to render PDF document.
  • and so on.
MY_URI
<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
 * MY_URI library for CodeIgniter
 *
 * @author		rock
 * @copyright	Copyright (c) 2008, Shih Yuncheng.
 * @license		http://codeigniter.com/user_guide/license.html
 * @link		http://blog.roodo.com/rocksaying
 * @since		Version 1.0
 * @filesource
 */

// ------------------------------------------------------------------------


/**
 * MY_URI Class
 *
 * Parses URIs and determines routing
 * Add file extension dection.
 *  
 * For example, if user request 'http://localhost/ci/blogs/index.xml'
 * it will try to load a view for XML.
 * 
 * In other cases:
 * If request 'blogs/index', load 'views/index.php' to render HTML document (default type).
 * If request 'blogs/index.xml', load 'views/index.xml.php' to render XML document.
 * If request 'blogs/index.pdf', load 'views/index.pdf.php' to render PDF document.
 * and so on.      
 *
 */

class MY_URI extends CI_URI {
	var $requestExt = false;   // The request extension name.


	/**
	 * Explode the URI Segments. The individual segments will
	 * be stored in the $this->segments array.	
	 *
	 * @access	private
	 * @return	void
	 */		
	function _explode_segments()
	{
		foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
		{
			// Filter segments for security

			$val = trim($this->_filter_uri($val));
			
			if ($val != '')
				$this->segments[] = $val;
		}

		$refLastSegment =& $this->segments[count($this->segments)-1];
		if ( preg_match('/(.+)\.(\w+)$/', $refLastSegment, $matches) ) {
			$refLastSegment = $matches[1];
			$this->requestExt = strtolower($matches[2]);
		}
	}

	// --------------------------------------------------------------------

	
	/**
	 * Fetch the file extension.
	 * 
	 * If user request 'http://localhost/ci_test/index.php/control/index.xml',
	 * this will return 'xml'.          	 
	 *
	 * @access	public
	 * @return	string
	 */
	function extension()
	{
		return $this->requestExt;
	}
}
// END URI Class

?>
MY_Loader
<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
 * MY_Loader library for CodeIgniter
 *
 * @author		rock
 * @copyright	Copyright (c) 2008, Shih Yuncheng.
 * @license		http://codeigniter.com/user_guide/license.html
 * @link		http://blog.roodo.com/rocksaying
 * @since		Version 1.0
 * @filesource
 */

// ------------------------------------------------------------------------


/**
 * MY_Loader Class
 *
 * Loads views and files
 */
class MY_Loader extends CI_Loader {
	/**
	 * Loader
	 *
	 * This function is used to load views and files.
	 * Variables are prefixed with _ci_ to avoid symbol collision with
	 * variables made available to view files
	 *
	 * @access	private
	 * @param	array
	 * @return	void
	 */
	function _ci_load($_ci_data)
	{
		$CI =& get_instance();
		@include(APPPATH.'config/mimes'.EXT);
		$docExt = $CI->uri->extension();

		// Set the default data variables

		foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val)
		{
			$$_ci_val = ( ! isset($_ci_data[$_ci_val])) ? FALSE : $_ci_data[$_ci_val];
		}

		// Set the path to the requested file

		$_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION);
		if ($_ci_path == '')
		{
			//$_ci_file = ($_ci_ext == '') ? $_ci_view.EXT : $_ci_view;

			if ($_ci_ext == '') {
				$_ci_file = $_ci_view 
					. ($docExt ? '.' . $docExt : '') 
					. EXT;
			}
			else {
				$_ci_file = $_ci_view; 
			}
			
			$_ci_path = $this->_ci_view_path . $_ci_file;
			
			if ( !file_exists($_ci_path) and $docExt == 'html') {
				$_ci_path = $this->_ci_view_path . $_ci_view . EXT;
			}
		}
		else
		{
			$_ci_x = explode('/', $_ci_path);
			$_ci_file = end($_ci_x);
		}
		
		if ( ! file_exists($_ci_path))
		{
			show_error('Unable to load the requested file: '.$_ci_file);
		}
	
		if ( $docExt and !isset($mimes[$docExt]) ) {
			show_error('The requested document type is not accepted: '.$docExt);
		}

		if ( $docExt and $_ci_ext == '') {
			$mimeType = $mimes[$docExt];
			$CI->output->set_header('Content-type: ' . $mimeType);
			log_message('debug', 'File MIME Type: ' . $mimeType);
		}

		// This allows anything loaded using $this->load (views, files, etc.)

		// to become accessible from within the Controller and Model functions.

		// Only needed when running PHP 5

		
		if ($this->_ci_is_instance())
		{
			$_ci_CI =& get_instance();
			foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var)
			{
				if ( ! isset($this->$_ci_key))
				{
					$this->$_ci_key =& $_ci_CI->$_ci_key;
				}
			}
		}

		/*
		 * Extract and cache variables
		 *
		 * You can either set variables using the dedicated $this->load_vars()
		 * function or via the second parameter of this function. We'll merge
		 * the two types and cache them so that views that are embedded within
		 * other views can have access to these variables.
		 */	
		if (is_array($_ci_vars))
		{
			$this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars);
		}
		extract($this->_ci_cached_vars);
				
		/*
		 * Buffer the output
		 *
		 * We buffer the output for two reasons:
		 * 1. Speed. You get a significant speed boost.
		 * 2. So that the final rendered template can be
		 * post-processed by the output class.  Why do we
		 * need post processing?  For one thing, in order to
		 * show the elapsed page load time.  Unless we
		 * can intercept the content right before it's sent to
		 * the browser and then stop the timer it won't be accurate.
		 */
		ob_start();
				
		// If the PHP installation does not support short tags we'll

		// do a little string replacement, changing the short tags

		// to standard PHP echo statements.

		
		if ((bool) @ini_get('short_open_tag') === FALSE AND config_item('rewrite_short_tags') == TRUE)
		{
			echo eval('?>'.preg_replace("/;*\s*\?>/", "; ?>", str_replace('<?=', '<?php echo ', file_get_contents($_ci_path))).'<?php ');
		}
		else
		{
			include($_ci_path);
		}
		
		log_message('debug', 'File loaded: '.$_ci_path);
		
		// Return the file data if requested

		if ($_ci_return === TRUE)
		{		
			$buffer = ob_get_contents();
			@ob_end_clean();
			return $buffer;
		}

		/*
		 * Flush the buffer... or buff the flusher?
		 *
		 * In order to permit views to be nested within
		 * other views, we need to flush the content back out whenever
		 * we are beyond the first level of output buffering so that
		 * it can be seen and included properly by the first included
		 * template and any subsequent ones. Oy!
		 *
		 */	
		if (ob_get_level() > $this->_ci_ob_level + 1)
		{
			ob_end_flush();
		}
		else
		{
			// PHP 4 requires that we use a global

			global $OUT;
			$OUT->append_output(ob_get_contents());
			@ob_end_clean();
		}
	}
}
// END Loader Class

?>
樂多舊網址: http://blog.roodo.com/rocksaying/archives/5573545.html