CodeIgniter - 如何有选择地缓存输出?

3
我的应用程序允许已注册用户发布内容。在顶部工具栏上,就像许多社交应用程序一样,在登录后可以看到其头像等内容。
我的问题是在使用CodeIgniter的输出缓存时,头部中的特定于用户的内容会被缓存。
这是因为我首先通过一个MY_Controller加载特定于用户的逻辑,然后由所有其他控制器扩展。
当我放置...
$this->output->cache(MINUTES);

在加载我的主页的控制器中,它还会缓存生成缓存页面的用户的头像和名称。是否有建议只选择缓存公共内容的最佳方法?如果需要,很高兴发布更多代码。
2个回答

3
我确定如果我错了,肯定会有人纠正我,但我相信codeigniter缓存仅允许缓存完整页面。还有一些额外的库可以实现部分页面缓存,请查看Phil Sturgeon在此方面的努力:http://getsparks.org/packages/cache/show 我的个人方法是不烦恼页面缓存,而只使用更具选择性的数据库缓存——但如果您需要页面缓存,则认为上述方法是唯一的可行途径。

不幸的是,Sturgeon的库对我似乎无效 - 我无法使其缓存一个数组 - 尽管缓存文件已创建,但它并不包含我的数据。 - pepe
1
这个怎么样?http://ellislab.com/forums/viewthread/69843/ 我知道有一些关于这个的,但我没有用过任何一个——我只是知道斯特金先生通常知道他在做什么。 - SwiftD
好的,这是我的错误 - 过期的配置 INT 是秒而不是分钟,所以我配置错误了 - 现在似乎需要弄清楚如何允许分页,因为缓存的主页只会加载自己而不是第2页,第3页等。 - pepe

1

Codeigniter不会将缓存分开处理访客和已验证用户。

你可以通过覆盖输出类来自行实现此功能。 在CI/application/core中创建MY_Output.php。

这是我最新项目的代码。

class MY_Output extends CI_Output

{

/**
 * Write Cache
 *
 * @param   string  $output Output data to cache
 * @return  void
 */
public function _write_cache($output)
{
    $CI =& get_instance();

    //-XXX CUSTOM------------------------------------
    $cache_path = $this->cachePath();
    //-----------------------------------------------

    if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))
    {
        log_message('error', 'Unable to write cache file: '.$cache_path);
        return;
    }

    $uri = $CI->config->item('base_url')
        .$CI->config->item('index_page')
        .$CI->uri->uri_string();

    if (($cache_query_string = $CI->config->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
    {
        if (is_array($cache_query_string))
        {
            $uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string)));
        }
        else
        {
            $uri .= '?'.$_SERVER['QUERY_STRING'];
        }
    }

    $cache_path .= md5($uri);

    if ( ! $fp = @fopen($cache_path, 'w+b'))
    {
        log_message('error', 'Unable to write cache file: '.$cache_path);
        return;
    }

    if ( ! flock($fp, LOCK_EX))
    {
        log_message('error', 'Unable to secure a file lock for file at: '.$cache_path);
        fclose($fp);
        return;
    }

    // If output compression is enabled, compress the cache
    // itself, so that we don't have to do that each time
    // we're serving it
    if ($this->_compress_output === TRUE)
    {
        $output = gzencode($output);

        if ($this->get_header('content-type') === NULL)
        {
            $this->set_content_type($this->mime_type);
        }
    }

    $expire = time() + ($this->cache_expiration * 60);

    // Put together our serialized info.
    $cache_info = serialize(array(
        'expire'    => $expire,
        'headers'   => $this->headers
    ));

    $output = $cache_info.'ENDCI--->'.$output;

    for ($written = 0, $length = self::strlen($output); $written < $length; $written += $result)
    {
        if (($result = fwrite($fp, self::substr($output, $written))) === FALSE)
        {
            break;
        }
    }

    flock($fp, LOCK_UN);
    fclose($fp);

    if ( ! is_int($result))
    {
        @unlink($cache_path);
        log_message('error', 'Unable to write the complete cache content at: '.$cache_path);
        return;
    }

    chmod($cache_path, 0640);
    log_message('debug', 'Cache file written: '.$cache_path);

    // Send HTTP cache-control headers to browser to match file cache settings.
    $this->set_cache_header($_SERVER['REQUEST_TIME'], $expire);
}

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

/**
 * Update/serve cached output
 *
 * @uses    CI_Config
 * @uses    CI_URI
 *
 * @param   object  &$CFG   CI_Config class instance
 * @param   object  &$URI   CI_URI class instance
 * @return  bool    TRUE on success or FALSE on failure
 */
public function _display_cache(&$CFG, &$URI)
{
    //-XXX CUSTOM------------------------------------
    $cache_path = $this->cachePath($CFG);
    //$cache_path = ($CFG->item('cache_path') === '') ? APPPATH.'cache/' : $CFG->item('cache_path');
    //-----------------------------------------------

    // Build the file path. The file name is an MD5 hash of the full URI
    $uri = $CFG->item('base_url').$CFG->item('index_page').$URI->uri_string;

    if (($cache_query_string = $CFG->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
    {
        if (is_array($cache_query_string))
        {
            $uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string)));
        }
        else
        {
            $uri .= '?'.$_SERVER['QUERY_STRING'];
        }
    }

    $filepath = $cache_path.md5($uri);

    if ( ! file_exists($filepath) OR ! $fp = @fopen($filepath, 'rb'))
    {
        return FALSE;
    }

    flock($fp, LOCK_SH);

    $cache = (filesize($filepath) > 0) ? fread($fp, filesize($filepath)) : '';

    flock($fp, LOCK_UN);
    fclose($fp);

    // Look for embedded serialized file info.
    if ( ! preg_match('/^(.*)ENDCI--->/', $cache, $match))
    {
        return FALSE;
    }

    $cache_info = unserialize($match[1]);
    $expire = $cache_info['expire'];

    $last_modified = filemtime($filepath);

    // Has the file expired?
    if ($_SERVER['REQUEST_TIME'] >= $expire && is_really_writable($cache_path))
    {
        // If so we'll delete it.
        @unlink($filepath);
        log_message('debug', 'Cache file has expired. File deleted.');
        return FALSE;
    }

    // Send the HTTP cache control headers
    $this->set_cache_header($last_modified, $expire);

    // Add headers from cache file.
    foreach ($cache_info['headers'] as $header)
    {
        $this->set_header($header[0], $header[1]);
    }

    //-XXX CUSTOM------------------------------------
    $exTime = $this->executionTime();
    setcookie('exe_time', "$exTime", time()+120, '/');
    //-----------------------------------------------

    // Display the cache
    $this->_display(self::substr($cache, self::strlen($match[0])));
    log_message('debug', 'Cache file is current. Sending it to browser.');
    return TRUE;
}

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

/**
 * Delete cache
 *
 * @param   string  $uri    URI string
 * @return  bool
 */
public function delete_cache($uri = '')
{
    $CI =& get_instance();
    //-XXX CUSTOM------------------------------------
    $cache_path = $CI->config->item('cache_path');
    $cache_path = ($cache_path === '') ? APPPATH.'cache/' : $cache_path;
    //-----------------------------------------------


    if ( ! is_dir($cache_path))
    {
        log_message('error', 'Unable to find cache path: '.$cache_path);
        return FALSE;
    }

    if (empty($uri))
    {
        $uri = $CI->uri->uri_string();

        if (($cache_query_string = $CI->config->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
        {
            if (is_array($cache_query_string))
            {
                $uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string)));
            }
            else
            {
                $uri .= '?'.$_SERVER['QUERY_STRING'];
            }
        }
    }


    //-XXX CUSTOM------------------------------------
    $passed = TRUE;
    $path1 = $cache_path.'xmember/'.md5($CI->config->item('base_url').$CI->config->item('index_page').ltrim($uri, '/'));
    if ( ! @unlink($path1))
    {
        log_message('error', 'Unable to delete cache file for '.$uri);
        $passed = FALSE;
    }

    $path2 = $cache_path.'xvisitor/'.md5($CI->config->item('base_url').$CI->config->item('index_page').ltrim($uri, '/'));
    if ( ! @unlink($path2))
    {
        log_message('error', 'Unable to delete cache file for '.$uri);
        $passed = FALSE;
    }
    //-----------------------------------------------

    return $passed;
}


private function cachePath(&$CFG=false)
{
    $hasSession = !empty($_COOKIE[COOKIE_CUSTOMER_SESSION_ID]);

    if(empty($CFG)) {
        $CI =& get_instance();
        $CFG = $CI->config;
    }
    $path = $CFG->item('cache_path');
    $path = empty($path) ? APPPATH.'cache/' : $path;
    $path .= $hasSession?'xmember/':'xvisitor/';

    return $path;
}

function executionTime()
{
    $time = microtime();
    $time = explode(' ', $time);
    $time = $time[1] + $time[0];
    $total_time = round(($time - LOAD_PAGE_START), 4); //second unit
    return $total_time;
}

}


最好能够给出一个使用示例,以展示如何进行分离。 - Pelin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接