Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like CI_Output often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use CI_Output, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
51 | View Code Duplication | class CI_Output { |
|
|
|||
52 | |||
53 | /** |
||
54 | * Final output string |
||
55 | * |
||
56 | * @var string |
||
57 | */ |
||
58 | public $final_output; |
||
59 | |||
60 | /** |
||
61 | * Cache expiration time |
||
62 | * |
||
63 | * @var int |
||
64 | */ |
||
65 | public $cache_expiration = 0; |
||
66 | |||
67 | /** |
||
68 | * List of server headers |
||
69 | * |
||
70 | * @var array |
||
71 | */ |
||
72 | public $headers = array(); |
||
73 | |||
74 | /** |
||
75 | * List of mime types |
||
76 | * |
||
77 | * @var array |
||
78 | */ |
||
79 | public $mimes = array(); |
||
80 | |||
81 | /** |
||
82 | * Mime-type for the current page |
||
83 | * |
||
84 | * @var string |
||
85 | */ |
||
86 | protected $mime_type = 'text/html'; |
||
87 | |||
88 | /** |
||
89 | * Enable Profiler flag |
||
90 | * |
||
91 | * @var bool |
||
92 | */ |
||
93 | public $enable_profiler = FALSE; |
||
94 | |||
95 | /** |
||
96 | * php.ini zlib.output_compression flag |
||
97 | * |
||
98 | * @var bool |
||
99 | */ |
||
100 | protected $_zlib_oc = FALSE; |
||
101 | |||
102 | /** |
||
103 | * CI output compression flag |
||
104 | * |
||
105 | * @var bool |
||
106 | */ |
||
107 | protected $_compress_output = FALSE; |
||
108 | |||
109 | /** |
||
110 | * List of profiler sections |
||
111 | * |
||
112 | * @var array |
||
113 | */ |
||
114 | protected $_profiler_sections = array(); |
||
115 | |||
116 | /** |
||
117 | * Parse markers flag |
||
118 | * |
||
119 | * Whether or not to parse variables like {elapsed_time} and {memory_usage}. |
||
120 | * |
||
121 | * @var bool |
||
122 | */ |
||
123 | public $parse_exec_vars = TRUE; |
||
124 | |||
125 | /** |
||
126 | * mbstring.func_overload flag |
||
127 | * |
||
128 | * @var bool |
||
129 | */ |
||
130 | protected static $func_overload; |
||
131 | |||
132 | /** |
||
133 | * Response status (status code, text and is redirection?) |
||
134 | * |
||
135 | * @var array |
||
136 | * |
||
137 | * added by ci-phpunit-test |
||
138 | */ |
||
139 | public $_status; |
||
140 | |||
141 | /** |
||
142 | * Cookies |
||
143 | * |
||
144 | * @var array |
||
145 | * |
||
146 | * added by ci-phpunit-test |
||
147 | */ |
||
148 | public $_cookies; |
||
149 | |||
150 | /** |
||
151 | * Class constructor |
||
152 | * |
||
153 | * Determines whether zLib output compression will be used. |
||
154 | * |
||
155 | * @return void |
||
156 | */ |
||
157 | public function __construct() |
||
158 | { |
||
159 | $this->_zlib_oc = (bool) ini_get('zlib.output_compression'); |
||
160 | $this->_compress_output = ( |
||
161 | $this->_zlib_oc === FALSE |
||
162 | && config_item('compress_output') === TRUE |
||
163 | && extension_loaded('zlib') |
||
164 | ); |
||
165 | |||
166 | isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload')); |
||
167 | |||
168 | // Get mime types for later |
||
169 | $this->mimes =& get_mimes(); |
||
170 | |||
171 | log_message('info', 'Output Class Initialized'); |
||
172 | } |
||
173 | |||
174 | // -------------------------------------------------------------------- |
||
175 | |||
176 | /** |
||
177 | * Get Output |
||
178 | * |
||
179 | * Returns the current output string. |
||
180 | * |
||
181 | * @return string |
||
182 | */ |
||
183 | public function get_output() |
||
184 | { |
||
185 | return $this->final_output; |
||
186 | } |
||
187 | |||
188 | // -------------------------------------------------------------------- |
||
189 | |||
190 | /** |
||
191 | * Set Output |
||
192 | * |
||
193 | * Sets the output string. |
||
194 | * |
||
195 | * @param string $output Output data |
||
196 | * @return CI_Output |
||
197 | */ |
||
198 | public function set_output($output) |
||
199 | { |
||
200 | $this->final_output = $output; |
||
201 | return $this; |
||
202 | } |
||
203 | |||
204 | // -------------------------------------------------------------------- |
||
205 | |||
206 | /** |
||
207 | * Append Output |
||
208 | * |
||
209 | * Appends data onto the output string. |
||
210 | * |
||
211 | * @param string $output Data to append |
||
212 | * @return CI_Output |
||
213 | */ |
||
214 | public function append_output($output) |
||
215 | { |
||
216 | $this->final_output .= $output; |
||
217 | return $this; |
||
218 | } |
||
219 | |||
220 | // -------------------------------------------------------------------- |
||
221 | |||
222 | /** |
||
223 | * Set Header |
||
224 | * |
||
225 | * Lets you set a server header which will be sent with the final output. |
||
226 | * |
||
227 | * Note: If a file is cached, headers will not be sent. |
||
228 | * @todo We need to figure out how to permit headers to be cached. |
||
229 | * |
||
230 | * @param string $header Header |
||
231 | * @param bool $replace Whether to replace the old header value, if already set |
||
232 | * @return CI_Output |
||
233 | */ |
||
234 | public function set_header($header, $replace = TRUE) |
||
235 | { |
||
236 | // If zlib.output_compression is enabled it will compress the output, |
||
237 | // but it will not modify the content-length header to compensate for |
||
238 | // the reduction, causing the browser to hang waiting for more data. |
||
239 | // We'll just skip content-length in those cases. |
||
240 | if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) === 0) |
||
241 | { |
||
242 | return $this; |
||
243 | } |
||
244 | |||
245 | $this->headers[] = array($header, $replace); |
||
246 | return $this; |
||
247 | } |
||
248 | |||
249 | // -------------------------------------------------------------------- |
||
250 | |||
251 | /** |
||
252 | * Set Content-Type Header |
||
253 | * |
||
254 | * @param string $mime_type Extension of the file we're outputting |
||
255 | * @param string $charset Character set (default: NULL) |
||
256 | * @return CI_Output |
||
257 | */ |
||
258 | public function set_content_type($mime_type, $charset = NULL) |
||
259 | { |
||
260 | if (strpos($mime_type, '/') === FALSE) |
||
261 | { |
||
262 | $extension = ltrim($mime_type, '.'); |
||
263 | |||
264 | // Is this extension supported? |
||
265 | if (isset($this->mimes[$extension])) |
||
266 | { |
||
267 | $mime_type =& $this->mimes[$extension]; |
||
268 | |||
269 | if (is_array($mime_type)) |
||
270 | { |
||
271 | $mime_type = current($mime_type); |
||
272 | } |
||
273 | } |
||
274 | } |
||
275 | |||
276 | $this->mime_type = $mime_type; |
||
277 | |||
278 | if (empty($charset)) |
||
279 | { |
||
280 | $charset = config_item('charset'); |
||
281 | } |
||
282 | |||
283 | $header = 'Content-Type: '.$mime_type |
||
284 | .(empty($charset) ? '' : '; charset='.$charset); |
||
285 | |||
286 | $this->headers[] = array($header, TRUE); |
||
287 | return $this; |
||
288 | } |
||
289 | |||
290 | // -------------------------------------------------------------------- |
||
291 | |||
292 | /** |
||
293 | * Get Current Content-Type Header |
||
294 | * |
||
295 | * @return string 'text/html', if not already set |
||
296 | */ |
||
297 | public function get_content_type() |
||
309 | |||
310 | // -------------------------------------------------------------------- |
||
311 | |||
312 | /** |
||
313 | * Get Header |
||
314 | * |
||
315 | * @param string $header |
||
316 | * @return string |
||
317 | */ |
||
318 | public function get_header($header) |
||
343 | |||
344 | // -------------------------------------------------------------------- |
||
345 | |||
346 | /** |
||
347 | * Set HTTP Status Header |
||
348 | * |
||
349 | * As of version 1.7.2, this is an alias for common function |
||
350 | * set_status_header(). |
||
351 | * |
||
352 | * @param int $code Status code (default: 200) |
||
353 | * @param string $text Optional message |
||
354 | * @return CI_Output |
||
355 | */ |
||
356 | public function set_status_header($code = 200, $text = '') |
||
357 | { |
||
358 | set_status_header($code, $text); |
||
359 | return $this; |
||
360 | } |
||
361 | |||
362 | // -------------------------------------------------------------------- |
||
363 | |||
364 | /** |
||
365 | * Enable/disable Profiler |
||
366 | * |
||
367 | * @param bool $val TRUE to enable or FALSE to disable |
||
368 | * @return CI_Output |
||
369 | */ |
||
370 | public function enable_profiler($val = TRUE) |
||
371 | { |
||
372 | $this->enable_profiler = is_bool($val) ? $val : TRUE; |
||
373 | return $this; |
||
374 | } |
||
375 | |||
376 | // -------------------------------------------------------------------- |
||
377 | |||
378 | /** |
||
379 | * Set Profiler Sections |
||
380 | * |
||
381 | * Allows override of default/config settings for |
||
382 | * Profiler section display. |
||
383 | * |
||
384 | * @param array $sections Profiler sections |
||
385 | * @return CI_Output |
||
386 | */ |
||
387 | public function set_profiler_sections($sections) |
||
388 | { |
||
389 | if (isset($sections['query_toggle_count'])) |
||
390 | { |
||
391 | $this->_profiler_sections['query_toggle_count'] = (int) $sections['query_toggle_count']; |
||
392 | unset($sections['query_toggle_count']); |
||
393 | } |
||
394 | |||
395 | foreach ($sections as $section => $enable) |
||
396 | { |
||
397 | $this->_profiler_sections[$section] = ($enable !== FALSE); |
||
398 | } |
||
399 | |||
400 | return $this; |
||
401 | } |
||
402 | |||
403 | // -------------------------------------------------------------------- |
||
404 | |||
405 | /** |
||
406 | * Set Cache |
||
407 | * |
||
408 | * @param int $time Cache expiration time in minutes |
||
409 | * @return CI_Output |
||
410 | */ |
||
411 | public function cache($time) |
||
412 | { |
||
413 | $this->cache_expiration = is_numeric($time) ? $time : 0; |
||
414 | return $this; |
||
415 | } |
||
416 | |||
417 | // -------------------------------------------------------------------- |
||
418 | |||
419 | /** |
||
420 | * Display Output |
||
421 | * |
||
422 | * Processes and sends finalized output data to the browser along |
||
423 | * with any server headers and profile data. It also stops benchmark |
||
424 | * timers so the page rendering speed and memory usage can be shown. |
||
425 | * |
||
426 | * Note: All "view" data is automatically put into $this->final_output |
||
427 | * by controller class. |
||
428 | * |
||
429 | * @uses CI_Output::$final_output |
||
430 | * @param string $output Output data override |
||
431 | * @return void |
||
432 | * |
||
433 | * modified by ci-phpunit-test |
||
434 | */ |
||
435 | public function _display($output = '') |
||
436 | { |
||
437 | // Note: We use load_class() because we can't use $CI =& get_instance() |
||
438 | // since this function is sometimes called by the caching mechanism, |
||
439 | // which happens before the CI super object is available. |
||
440 | $BM =& load_class('Benchmark', 'core'); |
||
441 | $CFG =& load_class('Config', 'core'); |
||
442 | |||
443 | // Grab the super object if we can. |
||
444 | if (class_exists('CI_Controller', FALSE)) |
||
445 | { |
||
446 | $CI =& get_instance(); |
||
447 | } |
||
448 | |||
449 | // -------------------------------------------------------------------- |
||
450 | |||
451 | // Set the output data |
||
452 | if ($output === '') |
||
453 | { |
||
454 | $output =& $this->final_output; |
||
455 | } |
||
456 | |||
457 | // -------------------------------------------------------------------- |
||
458 | |||
459 | // Do we need to write a cache file? Only if the controller does not have its |
||
460 | // own _output() method and we are not dealing with a cache file, which we |
||
461 | // can determine by the existence of the $CI object above |
||
462 | if ($this->cache_expiration > 0 && isset($CI) && ! method_exists($CI, '_output')) |
||
463 | { |
||
464 | $this->_write_cache($output); |
||
465 | } |
||
466 | |||
467 | // -------------------------------------------------------------------- |
||
468 | |||
469 | // Parse out the elapsed time and memory usage, |
||
470 | // then swap the pseudo-variables with the data |
||
471 | |||
472 | $elapsed = $BM->elapsed_time('total_execution_time_start', 'total_execution_time_end'); |
||
473 | |||
474 | if ($this->parse_exec_vars === TRUE) |
||
475 | { |
||
476 | $memory = round(memory_get_usage() / 1024 / 1024, 2).'MB'; |
||
477 | $output = str_replace(array('{elapsed_time}', '{memory_usage}'), array($elapsed, $memory), $output); |
||
478 | } |
||
479 | |||
480 | // -------------------------------------------------------------------- |
||
481 | |||
482 | // Is compression requested? |
||
483 | if (isset($CI) // This means that we're not serving a cache file, if we were, it would already be compressed |
||
484 | && $this->_compress_output === TRUE |
||
485 | && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE) |
||
486 | { |
||
487 | ob_start('ob_gzhandler'); |
||
488 | } |
||
489 | |||
490 | // -------------------------------------------------------------------- |
||
491 | |||
492 | // Are there any server headers to send? |
||
493 | if (count($this->headers) > 0) |
||
494 | { |
||
495 | foreach ($this->headers as $header) |
||
496 | { |
||
497 | // @header($header[0], $header[1]); |
||
498 | } |
||
499 | } |
||
500 | |||
501 | // -------------------------------------------------------------------- |
||
502 | |||
503 | // Does the $CI object exist? |
||
504 | // If not we know we are dealing with a cache file so we'll |
||
505 | // simply echo out the data and exit. |
||
506 | if ( ! isset($CI)) |
||
507 | { |
||
508 | if ($this->_compress_output === TRUE) |
||
509 | { |
||
510 | if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE) |
||
511 | { |
||
512 | // header('Content-Encoding: gzip'); |
||
513 | // header('Content-Length: '.self::strlen($output)); |
||
514 | } |
||
515 | else |
||
516 | { |
||
517 | // User agent doesn't support gzip compression, |
||
518 | // so we'll have to decompress our cache |
||
519 | $output = gzinflate(self::substr($output, 10, -8)); |
||
520 | } |
||
521 | } |
||
522 | |||
523 | echo $output; |
||
524 | log_message('info', 'Final output sent to browser'); |
||
525 | log_message('debug', 'Total execution time: '.$elapsed); |
||
526 | return; |
||
527 | } |
||
528 | |||
529 | // -------------------------------------------------------------------- |
||
530 | |||
531 | // Do we need to generate profile data? |
||
532 | // If so, load the Profile class and run it. |
||
533 | if ($this->enable_profiler === TRUE) |
||
534 | { |
||
535 | $CI->load->library('profiler'); |
||
536 | if ( ! empty($this->_profiler_sections)) |
||
537 | { |
||
538 | $CI->profiler->set_sections($this->_profiler_sections); |
||
539 | } |
||
540 | |||
541 | // If the output data contains closing </body> and </html> tags |
||
542 | // we will remove them and add them back after we insert the profile data |
||
543 | $output = preg_replace('|</body>.*?</html>|is', '', $output, -1, $count).$CI->profiler->run(); |
||
544 | if ($count > 0) |
||
545 | { |
||
546 | $output .= '</body></html>'; |
||
547 | } |
||
548 | } |
||
549 | |||
550 | // Does the controller contain a function named _output()? |
||
551 | // If so send the output there. Otherwise, echo it. |
||
552 | if (method_exists($CI, '_output')) |
||
553 | { |
||
554 | $CI->_output($output); |
||
555 | } |
||
556 | else |
||
557 | { |
||
558 | echo $output; // Send it to the browser! |
||
559 | } |
||
560 | |||
561 | log_message('info', 'Final output sent to browser'); |
||
562 | log_message('debug', 'Total execution time: '.$elapsed); |
||
563 | } |
||
564 | |||
565 | // -------------------------------------------------------------------- |
||
566 | |||
567 | /** |
||
568 | * Write Cache |
||
569 | * |
||
570 | * @param string $output Output data to cache |
||
571 | * @return void |
||
572 | */ |
||
573 | public function _write_cache($output) |
||
574 | { |
||
575 | $CI =& get_instance(); |
||
576 | $path = $CI->config->item('cache_path'); |
||
577 | $cache_path = ($path === '') ? APPPATH.'cache/' : $path; |
||
578 | |||
579 | if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path)) |
||
580 | { |
||
581 | log_message('error', 'Unable to write cache file: '.$cache_path); |
||
582 | return; |
||
583 | } |
||
584 | |||
585 | $uri = $CI->config->item('base_url') |
||
586 | .$CI->config->item('index_page') |
||
587 | .$CI->uri->uri_string(); |
||
588 | |||
589 | if (($cache_query_string = $CI->config->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING'])) |
||
590 | { |
||
591 | if (is_array($cache_query_string)) |
||
592 | { |
||
593 | $uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string))); |
||
594 | } |
||
595 | else |
||
596 | { |
||
597 | $uri .= '?'.$_SERVER['QUERY_STRING']; |
||
598 | } |
||
599 | } |
||
600 | |||
601 | $cache_path .= md5($uri); |
||
602 | |||
603 | if ( ! $fp = @fopen($cache_path, 'w+b')) |
||
604 | { |
||
605 | log_message('error', 'Unable to write cache file: '.$cache_path); |
||
606 | return; |
||
607 | } |
||
608 | |||
609 | if ( ! flock($fp, LOCK_EX)) |
||
610 | { |
||
611 | log_message('error', 'Unable to secure a file lock for file at: '.$cache_path); |
||
612 | fclose($fp); |
||
613 | return; |
||
614 | } |
||
615 | |||
616 | // If output compression is enabled, compress the cache |
||
617 | // itself, so that we don't have to do that each time |
||
618 | // we're serving it |
||
619 | if ($this->_compress_output === TRUE) |
||
620 | { |
||
621 | $output = gzencode($output); |
||
622 | |||
623 | if ($this->get_header('content-type') === NULL) |
||
624 | { |
||
625 | $this->set_content_type($this->mime_type); |
||
626 | } |
||
627 | } |
||
628 | |||
629 | $expire = time() + ($this->cache_expiration * 60); |
||
630 | |||
631 | // Put together our serialized info. |
||
632 | $cache_info = serialize(array( |
||
633 | 'expire' => $expire, |
||
634 | 'headers' => $this->headers |
||
635 | )); |
||
636 | |||
637 | $output = $cache_info.'ENDCI--->'.$output; |
||
638 | |||
639 | for ($written = 0, $length = self::strlen($output); $written < $length; $written += $result) |
||
640 | { |
||
641 | if (($result = fwrite($fp, self::substr($output, $written))) === FALSE) |
||
642 | { |
||
643 | break; |
||
644 | } |
||
645 | } |
||
646 | |||
647 | flock($fp, LOCK_UN); |
||
648 | fclose($fp); |
||
649 | |||
650 | if ( ! is_int($result)) |
||
651 | { |
||
652 | @unlink($cache_path); |
||
653 | log_message('error', 'Unable to write the complete cache content at: '.$cache_path); |
||
654 | return; |
||
655 | } |
||
656 | |||
657 | chmod($cache_path, 0640); |
||
658 | log_message('debug', 'Cache file written: '.$cache_path); |
||
659 | |||
660 | // Send HTTP cache-control headers to browser to match file cache settings. |
||
661 | $this->set_cache_header($_SERVER['REQUEST_TIME'], $expire); |
||
662 | } |
||
663 | |||
664 | // -------------------------------------------------------------------- |
||
665 | |||
666 | /** |
||
667 | * Update/serve cached output |
||
668 | * |
||
669 | * @uses CI_Config |
||
670 | * @uses CI_URI |
||
671 | * |
||
672 | * @param object &$CFG CI_Config class instance |
||
673 | * @param object &$URI CI_URI class instance |
||
674 | * @return bool TRUE on success or FALSE on failure |
||
675 | */ |
||
676 | public function _display_cache(&$CFG, &$URI) |
||
677 | { |
||
678 | $cache_path = ($CFG->item('cache_path') === '') ? APPPATH.'cache/' : $CFG->item('cache_path'); |
||
679 | |||
680 | // Build the file path. The file name is an MD5 hash of the full URI |
||
681 | $uri = $CFG->item('base_url').$CFG->item('index_page').$URI->uri_string; |
||
682 | |||
683 | if (($cache_query_string = $CFG->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING'])) |
||
684 | { |
||
685 | if (is_array($cache_query_string)) |
||
686 | { |
||
687 | $uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string))); |
||
688 | } |
||
689 | else |
||
690 | { |
||
691 | $uri .= '?'.$_SERVER['QUERY_STRING']; |
||
692 | } |
||
693 | } |
||
694 | |||
695 | $filepath = $cache_path.md5($uri); |
||
696 | |||
697 | if ( ! file_exists($filepath) OR ! $fp = @fopen($filepath, 'rb')) |
||
698 | { |
||
699 | return FALSE; |
||
700 | } |
||
701 | |||
702 | flock($fp, LOCK_SH); |
||
703 | |||
704 | $cache = (filesize($filepath) > 0) ? fread($fp, filesize($filepath)) : ''; |
||
705 | |||
706 | flock($fp, LOCK_UN); |
||
707 | fclose($fp); |
||
708 | |||
709 | // Look for embedded serialized file info. |
||
710 | if ( ! preg_match('/^(.*)ENDCI--->/', $cache, $match)) |
||
711 | { |
||
712 | return FALSE; |
||
713 | } |
||
714 | |||
715 | $cache_info = unserialize($match[1]); |
||
716 | $expire = $cache_info['expire']; |
||
717 | |||
718 | $last_modified = filemtime($filepath); |
||
719 | |||
720 | // Has the file expired? |
||
721 | if ($_SERVER['REQUEST_TIME'] >= $expire && is_really_writable($cache_path)) |
||
722 | { |
||
723 | // If so we'll delete it. |
||
724 | @unlink($filepath); |
||
725 | log_message('debug', 'Cache file has expired. File deleted.'); |
||
726 | return FALSE; |
||
727 | } |
||
728 | |||
729 | // Send the HTTP cache control headers |
||
730 | $this->set_cache_header($last_modified, $expire); |
||
731 | |||
732 | // Add headers from cache file. |
||
733 | foreach ($cache_info['headers'] as $header) |
||
734 | { |
||
735 | $this->set_header($header[0], $header[1]); |
||
736 | } |
||
737 | |||
738 | // Display the cache |
||
739 | $this->_display(self::substr($cache, self::strlen($match[0]))); |
||
740 | log_message('debug', 'Cache file is current. Sending it to browser.'); |
||
741 | return TRUE; |
||
742 | } |
||
743 | |||
744 | // -------------------------------------------------------------------- |
||
745 | |||
746 | /** |
||
747 | * Delete cache |
||
748 | * |
||
749 | * @param string $uri URI string |
||
750 | * @return bool |
||
751 | */ |
||
752 | public function delete_cache($uri = '') |
||
794 | |||
795 | // -------------------------------------------------------------------- |
||
796 | |||
797 | /** |
||
798 | * Set Cache Header |
||
799 | * |
||
800 | * Set the HTTP headers to match the server-side file cache settings |
||
801 | * in order to reduce bandwidth. |
||
802 | * |
||
803 | * @param int $last_modified Timestamp of when the page was last modified |
||
804 | * @param int $expiration Timestamp of when should the requested page expire from cache |
||
805 | * @return void |
||
806 | * |
||
807 | * modified by ci-phpunit-test |
||
808 | */ |
||
809 | public function set_cache_header($last_modified, $expiration) |
||
824 | |||
825 | // -------------------------------------------------------------------- |
||
826 | |||
827 | /** |
||
828 | * Byte-safe strlen() |
||
829 | * |
||
830 | * @param string $str |
||
831 | * @return int |
||
832 | */ |
||
833 | protected static function strlen($str) |
||
839 | |||
840 | // -------------------------------------------------------------------- |
||
841 | |||
842 | /** |
||
843 | * Byte-safe substr() |
||
844 | * |
||
845 | * @param string $str |
||
846 | * @param int $start |
||
847 | * @param int $length |
||
848 | * @return string |
||
849 | */ |
||
850 | protected static function substr($str, $start, $length = NULL) |
||
864 | } |
||
865 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.