1<?php
2/**
3 * Joomla! Content Management System
4 *
5 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
6 * @license    GNU General Public License version 2 or later; see LICENSE.txt
7 */
8
9namespace Joomla\CMS\Cache\Controller;
10
11defined('JPATH_PLATFORM') or die;
12
13use Joomla\CMS\Cache\CacheController;
14use Joomla\CMS\Log\Log;
15
16/**
17 * Joomla Cache output type object
18 *
19 * @since  1.7.0
20 */
21class OutputController extends CacheController
22{
23	/**
24	 * Cache data ID
25	 *
26	 * @var    string
27	 * @since  1.7.0
28	 */
29	protected $_id;
30
31	/**
32	 * Cache data group
33	 *
34	 * @var    string
35	 * @since  1.7.0
36	 */
37	protected $_group;
38
39	/**
40	 * Object to test locked state
41	 *
42	 * @var    \stdClass
43	 * @since  1.7.0
44	 * @deprecated  4.0
45	 */
46	protected $_locktest = null;
47
48	/**
49	 * Start the cache
50	 *
51	 * @param   string  $id     The cache data ID
52	 * @param   string  $group  The cache data group
53	 *
54	 * @return  boolean
55	 *
56	 * @since   1.7.0
57	 * @deprecated  4.0
58	 */
59	public function start($id, $group = null)
60	{
61		Log::add(
62			__METHOD__ . '() is deprecated.',
63			Log::WARNING,
64			'deprecated'
65		);
66
67		// If we have data in cache use that.
68		$data = $this->cache->get($id, $group);
69
70		$this->_locktest             = new \stdClass;
71		$this->_locktest->locked     = null;
72		$this->_locktest->locklooped = null;
73
74		if ($data === false)
75		{
76			$this->_locktest = $this->cache->lock($id, $group);
77
78			if ($this->_locktest->locked == true && $this->_locktest->locklooped == true)
79			{
80				$data = $this->cache->get($id, $group);
81			}
82		}
83
84		if ($data !== false)
85		{
86			$data = unserialize(trim($data));
87			echo $data;
88
89			if ($this->_locktest->locked == true)
90			{
91				$this->cache->unlock($id, $group);
92			}
93
94			return true;
95		}
96
97		// Nothing in cache... let's start the output buffer and start collecting data for next time.
98		if ($this->_locktest->locked == false)
99		{
100			$this->_locktest = $this->cache->lock($id, $group);
101		}
102
103		ob_start();
104		ob_implicit_flush(false);
105
106		// Set id and group placeholders
107		$this->_id = $id;
108		$this->_group = $group;
109
110		return false;
111	}
112
113	/**
114	 * Stop the cache buffer and store the cached data
115	 *
116	 * @return  boolean  True if the cache data was stored
117	 *
118	 * @since   1.7.0
119	 * @deprecated  4.0
120	 */
121	public function end()
122	{
123		Log::add(
124			__METHOD__ . '() is deprecated.',
125			Log::WARNING,
126			'deprecated'
127		);
128
129		// Get data from output buffer and echo it
130		$data = ob_get_clean();
131		echo $data;
132
133		// Get the ID and group and reset the placeholders
134		$id           = $this->_id;
135		$group        = $this->_group;
136		$this->_id    = null;
137		$this->_group = null;
138
139		// Get the storage handler and store the cached data
140		$ret = $this->cache->store(serialize($data), $id, $group);
141
142		if ($this->_locktest->locked == true)
143		{
144			$this->cache->unlock($id, $group);
145		}
146
147		return $ret;
148	}
149
150	/**
151	 * Get stored cached data by ID and group
152	 *
153	 * @param   string  $id     The cache data ID
154	 * @param   string  $group  The cache data group
155	 *
156	 * @return  mixed  Boolean false on no result, cached object otherwise
157	 *
158	 * @since   1.7.0
159	 */
160	public function get($id, $group = null)
161	{
162		$data = $this->cache->get($id, $group);
163
164		if ($data === false)
165		{
166			$locktest = $this->cache->lock($id, $group);
167
168			// If locklooped is true try to get the cached data again; it could exist now.
169			if ($locktest->locked === true && $locktest->locklooped === true)
170			{
171				$data = $this->cache->get($id, $group);
172			}
173
174			if ($locktest->locked === true)
175			{
176				$this->cache->unlock($id, $group);
177			}
178		}
179
180		// Check again because we might get it from second attempt
181		if ($data !== false)
182		{
183			// Trim to fix unserialize errors
184			$data = unserialize(trim($data));
185		}
186
187		return $data;
188	}
189
190	/**
191	 * Store data to cache by ID and group
192	 *
193	 * @param   mixed    $data        The data to store
194	 * @param   string   $id          The cache data ID
195	 * @param   string   $group       The cache data group
196	 * @param   boolean  $wrkarounds  True to use wrkarounds
197	 *
198	 * @return  boolean  True if cache stored
199	 *
200	 * @since   1.7.0
201	 */
202	public function store($data, $id, $group = null, $wrkarounds = true)
203	{
204		$locktest = $this->cache->lock($id, $group);
205
206		if ($locktest->locked === false && $locktest->locklooped === true)
207		{
208			// We can not store data because another process is in the middle of saving
209			return false;
210		}
211
212		$result = $this->cache->store(serialize($data), $id, $group);
213
214		if ($locktest->locked === true)
215		{
216			$this->cache->unlock($id, $group);
217		}
218
219		return $result;
220	}
221}
222