Likes::msgIssueLike()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
c 0
b 0
f 0
nop 0
dl 0
loc 14
rs 10
nc 2
1
<?php
2
3
/**
4
 * This file contains liking posts and displaying the list of who liked a post.
5
 *
6
 * Simple Machines Forum (SMF)
7
 *
8
 * @package SMF
9
 * @author Simple Machines https://www.simplemachines.org
10
 * @copyright 2022 Simple Machines and individual contributors
11
 * @license https://www.simplemachines.org/about/smf/license.php BSD
12
 *
13
 * @version 2.1.0
14
 */
15
16
if (!defined('SMF'))
17
	die('No direct access...');
18
19
/**
20
 * Class Likes
21
 */
22
class Likes
23
{
24
	/**
25
	 * @var boolean Know if a request comes from an ajax call or not, depends on $_GET['js'] been set.
26
	 */
27
	protected $_js = false;
28
29
	/**
30
	 * @var string If filled, its value will contain a string matching a key on a language var $txt[$this->_error]
31
	 */
32
	protected $_error = false;
33
34
	/**
35
	 * @var string The unique type to like, needs to be unique and it needs to be no longer than 6 characters, only numbers and letters are allowed.
36
	 */
37
	protected $_type = '';
38
39
	/**
40
	 * @var string A generic string used if you need to pass any extra info. It gets set via $_GET['extra'].
41
	 */
42
	protected $_extra = false;
43
44
	/**
45
	 * @var integer a valid ID to identify your like content.
46
	 */
47
	protected $_content = 0;
48
49
	/**
50
	 * @var integer The number of times your content has been liked.
51
	 */
52
	protected $_numLikes = 0;
53
54
	/**
55
	 * @var boolean If the current user has already liked this content.
56
	 */
57
	protected $_alreadyLiked = false;
58
59
	/**
60
	 * @var array $_validLikes mostly used for external integration, needs to be filled as an array with the following keys:
61
	 * => 'can_like' boolean|string whether or not the current user can actually like your content.
62
	 * for can_like: Return a boolean true if the user can, otherwise return a string, the string will be used as key in a regular $txt language error var. The code assumes you already loaded your language file. If no value is returned or the $txt var isn't set, the code will use a generic error message.
63
	 * => 'redirect' string To add support for non JS users, It is highly encouraged to set a valid URL to redirect the user to, if you don't provide any, the code will redirect the user to the main page. The code only performs a light check to see if the redirect is valid so be extra careful while building it.
64
	 * => 'type' string 6 letters or numbers. The unique identifier for your content, the code doesn't check for duplicate entries, if there are 2 or more exact hook calls, the code will take the first registered one so make sure you provide a unique identifier. Must match with what you sent in $_GET['ltype'].
65
	 * => 'flush_cache' boolean this is optional, it tells the code to reset your like content's cache entry after a new entry has been inserted.
66
	 * => 'callback' callable optional, useful if you don't want to issue a separate hook for updating your data, it is called immediately after the data was inserted or deleted and before the actual hook. Uses call_helper(); so the same format for your function/method can be applied here.
67
	 * => 'json' boolean optional defaults to false, if true the Like class will return a json object as response instead of HTML.
68
	 */
69
	protected $_validLikes = array(
70
		'can_like' => false,
71
		'redirect' => '',
72
		'type' => '',
73
		'flush_cache' => '',
74
		'callback' => false,
75
		'json' => false,
76
	);
77
78
	/**
79
	 * @var array The current user info ($user_info).
80
	 */
81
	protected $_user;
82
83
	/**
84
	 * @var integer The topic ID, used for liking messages.
85
	 */
86
	protected $_idTopic = 0;
87
88
	/**
89
	 * @var boolean to know if response(); will be executed as normal. If this is set to false it indicates the method already solved its own way to send back a response.
90
	 */
91
	protected $_setResponse = true;
92
93
	/**
94
	 * Likes::__construct()
95
	 *
96
	 * Sets the basic data needed for the rest of the process.
97
	 */
98
	public function __construct()
99
	{
100
		global $db_show_debug;
101
102
		$this->_type = isset($_GET['ltype']) ? $_GET['ltype'] : '';
103
		$this->_content = isset($_GET['like']) ? (int) $_GET['like'] : 0;
104
		$this->_js = isset($_GET['js']) ? true : false;
105
		$this->_sa = isset($_GET['sa']) ? $_GET['sa'] : 'like';
0 ignored issues
show
Bug Best Practice introduced by
The property _sa does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
106
		$this->_extra = isset($_GET['extra']) ? $_GET['extra'] : false;
0 ignored issues
show
Documentation Bug introduced by
It seems like IssetNode ? $_GET['extra'] : false can also be of type false. However, the property $_extra is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
107
108
		// We do not want to output debug information here.
109
		if ($this->_js)
110
			$db_show_debug = false;
111
	}
112
113
	/**
114
	 * Likes::call()
115
	 *
116
	 * The main handler. Verifies permissions (whether the user can see the content in question), dispatch different method for different sub-actions.
117
	 * Accessed from index.php?action=likes
118
	 */
119
	public function call()
120
	{
121
		global $context;
122
123
		$this->_user = $context['user'];
124
125
		// Make sure the user can see and like your content.
126
		$this->check();
127
128
		$subActions = array(
129
			'like',
130
			'view',
131
			'delete',
132
			'insert',
133
			'_count',
134
		);
135
136
		// So at this point, whatever type of like the user supplied and the item of content in question,
137
		// we know it exists, now we need to figure out what we're doing with that.
138
		if (in_array($this->_sa, $subActions) && !is_string($this->_error))
0 ignored issues
show
introduced by
The condition is_string($this->_error) is always true.
Loading history...
139
		{
140
			// To avoid ambiguity, turn the property to a normal var.
141
			$call = $this->_sa;
142
143
			// Guest can only view likes.
144
			if ($call != 'view')
145
				is_not_guest();
146
147
			checkSession('get');
148
149
			// Call the appropriate method.
150
			$this->$call();
151
		}
152
153
		// else An error message.
154
		$this->response();
155
	}
156
157
	/**
158
	 * Likes::get()
159
	 *
160
	 * A simple getter for all protected properties.
161
	 * Accessed from index.php?action=likes
162
	 *
163
	 * @param string $property The name of the property to get.
164
	 * @return mixed Either return the property or false if there isn't a property with that name.
165
	 */
166
	public function get($property = '')
167
	{
168
		// All properties inside Likes are protected, thus, an underscore is used.
169
		$property = '_' . $property;
170
		return property_exists($this, $property) ? $this->$property : false;
171
	}
172
173
	/**
174
	 * Likes::check()
175
	 *
176
	 * Performs basic checks on the data provided, checks for a valid msg like.
177
	 * Calls integrate_valid_likes hook for retrieving all the data needed and apply checks based on the data provided.
178
	 */
179
	protected function check()
180
	{
181
		global $smcFunc, $modSettings;
182
183
		// This feature is currently disable.
184
		if (empty($modSettings['enable_likes']))
185
			return $this->_error = 'like_disable';
186
187
		// Zerothly, they did indicate some kind of content to like, right?
188
		preg_match('~^([a-z0-9\-\_]{1,6})~i', $this->_type, $matches);
189
		$this->_type = isset($matches[1]) ? $matches[1] : '';
190
191
		if ($this->_type == '' || $this->_content <= 0)
192
			return $this->_error = 'cannot_';
193
194
		// First we need to verify if the user can see the type of content or not. This is set up to be extensible,
195
		// so we'll check for the one type we do know about, and if it's not that, we'll defer to any hooks.
196
		if ($this->_type == 'msg')
197
		{
198
			// So we're doing something off a like. We need to verify that it exists, and that the current user can see it.
199
			// Fortunately for messages, this is quite easy to do - and we'll get the topic id while we're at it, because
200
			// we need this later for other things.
201
			$request = $smcFunc['db_query']('', '
202
				SELECT m.id_topic, m.id_member
203
				FROM {db_prefix}messages AS m
204
				WHERE {query_see_message_board}
205
					AND m.id_msg = {int:msg}',
206
				array(
207
					'msg' => $this->_content,
208
				)
209
			);
210
			if ($smcFunc['db_num_rows']($request) == 1)
211
				list ($this->_idTopic, $topicOwner) = $smcFunc['db_fetch_row']($request);
212
213
			$smcFunc['db_free_result']($request);
214
			if (empty($this->_idTopic))
215
				return $this->_error = 'cannot_';
216
217
			// So we know what topic it's in and more importantly we know the user can see it.
218
			// If we're not viewing, we need some info set up.
219
			$this->_validLikes['type'] = 'msg';
220
			$this->_validLikes['flush_cache'] = 'likes_topic_' . $this->_idTopic . '_' . $this->_user['id'];
221
			$this->_validLikes['redirect'] = 'topic=' . $this->_idTopic . '.msg' . $this->_content . '#msg' . $this->_content;
222
223
			$this->_validLikes['can_like'] = ($this->_user['id'] == $topicOwner ? 'cannot_like_content' : (allowedTo('likes_like') ? true : 'cannot_like_content'));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $topicOwner does not seem to be defined for all execution paths leading up to this point.
Loading history...
224
		}
225
226
		else
227
		{
228
			// Modders: This will give you whatever the user offers up in terms of liking, e.g. $this->_type=msg, $this->_content=1
229
			// When you hook this, check $this->_type first. If it is not something your mod worries about, return false.
230
			// Otherwise, fill an array according to the docs for $this->_validLikes. Determine (however you need to) that the user can see and can_like the relevant liked content (and it exists) Remember that users can't like their own content.
231
			// If the user can like it, you MUST return your type in the 'type' key back.
232
			// See also issueLike() for further notes.
233
			$can_like = call_integration_hook('integrate_valid_likes', array($this->_type, $this->_content, $this->_sa, $this->_js, $this->_extra));
234
235
			$found = false;
236
			if (!empty($can_like))
237
			{
238
				$can_like = (array) $can_like;
239
				foreach ($can_like as $result)
240
				{
241
					if ($result !== false)
242
					{
243
						// Match the type with what we already have.
244
						if (!isset($result['type']) || $result['type'] != $this->_type)
245
							return $this->_error = 'not_valid_like_type';
246
247
						// Fill out the rest.
248
						$this->_type = $result['type'];
249
						$this->_validLikes = array_merge($this->_validLikes, $result);
250
						$found = true;
251
						break;
252
					}
253
				}
254
			}
255
256
			if (!$found)
257
				return $this->_error = 'cannot_';
258
		}
259
260
		// Does the user can like this? Viewing a list of likes doesn't require this permission.
261
		if ($this->_sa != 'view' && isset($this->_validLikes['can_like']) && is_string($this->_validLikes['can_like']))
262
			return $this->_error = $this->_validLikes['can_like'];
263
	}
264
265
	/**
266
	 * Likes::delete()
267
	 *
268
	 * Deletes an entry from user_likes table, needs 3 properties: $_content, $_type and $_user['id'].
269
	 */
270
	protected function delete()
271
	{
272
		global $smcFunc;
273
274
		$smcFunc['db_query']('', '
275
			DELETE FROM {db_prefix}user_likes
276
			WHERE content_id = {int:like_content}
277
				AND content_type = {string:like_type}
278
				AND id_member = {int:id_member}',
279
			array(
280
				'like_content' => $this->_content,
281
				'like_type' => $this->_type,
282
				'id_member' => $this->_user['id'],
283
			)
284
		);
285
286
		// Are we calling this directly? if so, set a proper data for the response. Do note that __METHOD__ returns both the class name and the function name.
287
		if ($this->_sa == __FUNCTION__)
288
			$this->_data = __FUNCTION__;
0 ignored issues
show
Bug Best Practice introduced by
The property _data does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
289
	}
290
291
	/**
292
	 * Likes::insert()
293
	 *
294
	 * Inserts a new entry on user_likes table. Creates a background task for the inserted entry.
295
	 */
296
	protected function insert()
297
	{
298
		global $smcFunc;
299
300
		// Any last minute changes? Temporarily turn the passed properties to normal vars to prevent unexpected behaviour with other methods using these properties.
301
		$type = $this->_type;
302
		$content = $this->_content;
303
		$user = $this->_user;
304
		$time = time();
305
306
		call_integration_hook('integrate_issue_like_before', array(&$type, &$content, &$user, &$time));
307
308
		// Insert the like.
309
		$smcFunc['db_insert']('insert',
310
			'{db_prefix}user_likes',
311
			array('content_id' => 'int', 'content_type' => 'string-6', 'id_member' => 'int', 'like_time' => 'int'),
312
			array($content, $type, $user['id'], $time),
313
			array('content_id', 'content_type', 'id_member')
314
		);
315
316
		// Add a background task to process sending alerts.
317
		// Mod author, you can add your own background task for your own custom like event using the "integrate_issue_like" hook or your callback, both are immediately called after this.
318
		if ($this->_type == 'msg')
319
			$smcFunc['db_insert']('insert',
320
				'{db_prefix}background_tasks',
321
				array('task_file' => 'string', 'task_class' => 'string', 'task_data' => 'string', 'claimed_time' => 'int'),
322
				array('$sourcedir/tasks/Likes-Notify.php', 'Likes_Notify_Background', $smcFunc['json_encode'](array(
323
					'content_id' => $content,
324
					'content_type' => $type,
325
					'sender_id' => $user['id'],
326
					'sender_name' => $user['name'],
327
					'time' => $time,
328
				)), 0),
329
				array('id_task')
330
			);
331
332
		// Are we calling this directly? if so, set a proper data for the response. Do note that __METHOD__ returns both the class name and the function name.
333
		if ($this->_sa == __FUNCTION__)
334
			$this->_data = __FUNCTION__;
0 ignored issues
show
Bug Best Practice introduced by
The property _data does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
335
	}
336
337
	/**
338
	 * Likes::_count()
339
	 *
340
	 * Sets $_numLikes with the actual number of likes your content has, needs two properties: $_content and $_view. When called directly it will return the number of likes as response.
341
	 */
342
	protected function _count()
343
	{
344
		global $smcFunc;
345
346
		$request = $smcFunc['db_query']('', '
347
			SELECT COUNT(*)
348
			FROM {db_prefix}user_likes
349
			WHERE content_id = {int:like_content}
350
				AND content_type = {string:like_type}',
351
			array(
352
				'like_content' => $this->_content,
353
				'like_type' => $this->_type,
354
			)
355
		);
356
		list ($this->_numLikes) = $smcFunc['db_fetch_row']($request);
357
		$smcFunc['db_free_result']($request);
358
359
		// If you want to call this directly, fill out _data property too.
360
		if ($this->_sa == __FUNCTION__)
361
			$this->_data = $this->_numLikes;
0 ignored issues
show
Bug Best Practice introduced by
The property _data does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
362
	}
363
364
	/**
365
	 * Likes::like()
366
	 *
367
	 * Performs a like action, either like or unlike. Counts the total of likes and calls a hook after the event.
368
	 */
369
	protected function like()
370
	{
371
		global $smcFunc;
372
373
		// Safety first!
374
		if (empty($this->_type) || empty($this->_content))
375
			return $this->_error = 'cannot_';
376
377
		// Do we already like this?
378
		$request = $smcFunc['db_query']('', '
379
			SELECT content_id, content_type, id_member
380
			FROM {db_prefix}user_likes
381
			WHERE content_id = {int:like_content}
382
				AND content_type = {string:like_type}
383
				AND id_member = {int:id_member}',
384
			array(
385
				'like_content' => $this->_content,
386
				'like_type' => $this->_type,
387
				'id_member' => $this->_user['id'],
388
			)
389
		);
390
		$this->_alreadyLiked = (bool) $smcFunc['db_num_rows']($request) != 0;
391
		$smcFunc['db_free_result']($request);
392
393
		if ($this->_alreadyLiked)
394
			$this->delete();
395
396
		else
397
			$this->insert();
398
399
		// Now, how many people like this content now? We *could* just +1 / -1 the relevant container but that has proven to become unstable.
400
		$this->_count();
401
402
		// Update the likes count for messages.
403
		if ($this->_type == 'msg')
404
			$this->msgIssueLike();
405
406
		// Any callbacks?
407
		elseif (!empty($this->_validLikes['callback']))
408
		{
409
			$call = call_helper($this->_validLikes['callback'], true);
410
411
			if (!empty($call))
412
				call_user_func_array($call, array($this));
0 ignored issues
show
Bug introduced by
It seems like $call can also be of type boolean; however, parameter $callback of call_user_func_array() does only seem to accept callable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

412
				call_user_func_array(/** @scrutinizer ignore-type */ $call, array($this));
Loading history...
413
		}
414
415
		// Sometimes there might be other things that need updating after we do this like.
416
		call_integration_hook('integrate_issue_like', array($this));
417
418
		// Now some clean up. This is provided here for any like handlers that want to do any cache flushing.
419
		// This way a like handler doesn't need to explicitly declare anything in integrate_issue_like, but do so
420
		// in integrate_valid_likes where it absolutely has to exist.
421
		if (!empty($this->_validLikes['flush_cache']))
422
			cache_put_data($this->_validLikes['flush_cache'], null);
423
424
		// All done, start building the data to pass as response.
425
		$this->_data = array(
0 ignored issues
show
Bug Best Practice introduced by
The property _data does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
426
			'id_topic' => !empty($this->_idTopic) ? $this->_idTopic : 0,
427
			'id_content' => $this->_content,
428
			'count' => $this->_numLikes,
429
			'can_like' => $this->_validLikes['can_like'],
430
			'already_liked' => empty($this->_alreadyLiked),
431
			'type' => $this->_type,
432
		);
433
	}
434
435
	/**
436
	 * Likes::msgIssueLike()
437
	 *
438
	 * Partly it indicates how it's supposed to work and partly it deals with updating the count of likes
439
	 * attached to this message now.
440
	 */
441
	function msgIssueLike()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
442
	{
443
		global $smcFunc;
444
445
		if ($this->_type !== 'msg')
446
			return;
447
448
		$smcFunc['db_query']('', '
449
			UPDATE {db_prefix}messages
450
			SET likes = {int:num_likes}
451
			WHERE id_msg = {int:id_msg}',
452
			array(
453
				'id_msg' => $this->_content,
454
				'num_likes' => $this->_numLikes,
455
			)
456
		);
457
458
		// Note that we could just as easily have cleared the cache here, or set up the redirection address
459
		// but if your liked content doesn't need to do anything other than have the record in smf_user_likes,
460
		// there's no point in creating another function unnecessarily.
461
	}
462
463
	/**
464
	 * Likes::view()
465
	 *
466
	 * This is for viewing the people who liked a thing.
467
	 * Accessed from index.php?action=likes;view and should generally load in a popup.
468
	 * We use a template for this in case themers want to style it.
469
	 */
470
	function view()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
471
	{
472
		global $smcFunc, $txt, $context, $memberContext;
473
474
		// Firstly, load what we need. We already know we can see this, so that's something.
475
		$context['likers'] = array();
476
		$request = $smcFunc['db_query']('', '
477
			SELECT id_member, like_time
478
			FROM {db_prefix}user_likes
479
			WHERE content_id = {int:like_content}
480
				AND content_type = {string:like_type}
481
			ORDER BY like_time DESC',
482
			array(
483
				'like_content' => $this->_content,
484
				'like_type' => $this->_type,
485
			)
486
		);
487
		while ($row = $smcFunc['db_fetch_assoc']($request))
488
			$context['likers'][$row['id_member']] = array('timestamp' => $row['like_time']);
489
490
		// Now to get member data, including avatars and so on.
491
		$members = array_keys($context['likers']);
492
		$loaded = loadMemberData($members);
493
		if (count($loaded) != count($members))
494
		{
495
			$members = array_diff($members, $loaded);
496
			foreach ($members as $not_loaded)
497
				unset ($context['likers'][$not_loaded]);
498
		}
499
500
		foreach ($context['likers'] as $liker => $dummy)
501
		{
502
			$loaded = loadMemberContext($liker);
503
			if (!$loaded)
504
			{
505
				unset ($context['likers'][$liker]);
506
				continue;
507
			}
508
509
			$context['likers'][$liker]['profile'] = &$memberContext[$liker];
510
			$context['likers'][$liker]['time'] = !empty($dummy['timestamp']) ? timeformat($dummy['timestamp']) : '';
511
		}
512
513
		$count = count($context['likers']);
514
		$title_base = isset($txt['likes_' . $count]) ? 'likes_' . $count : 'likes_n';
515
		$context['page_title'] = strip_tags(sprintf($txt[$title_base], '', comma_format($count)));
516
517
		// Lastly, setting up for display.
518
		loadTemplate('Likes');
519
		loadLanguage('Help'); // For the close window button.
520
		$context['template_layers'] = array();
521
		$context['sub_template'] = 'popup';
522
523
		// We already took care of our response so there is no need to bother with respond();
524
		$this->_setResponse = false;
525
	}
526
527
	/**
528
	 * Likes::response()
529
	 *
530
	 * Checks if the user can use JavaScript and acts accordingly.
531
	 * Calls the appropriate sub-template for each method
532
	 * Handles error messages.
533
	 */
534
	protected function response()
535
	{
536
		global $context, $txt;
537
538
		// Don't do anything if someone else has already take care of the response.
539
		if (!$this->_setResponse)
540
			return;
541
542
		// Want a json response huh?
543
		if ($this->_validLikes['json'])
544
			return $this->jsonResponse();
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->jsonResponse() targeting Likes::jsonResponse() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
545
546
		// Set everything up for display.
547
		loadTemplate('Likes');
548
		$context['template_layers'] = array();
549
550
		// If there are any errors, process them first.
551
		if ($this->_error)
552
		{
553
			// If this is a generic error, set it up good.
554
			if ($this->_error == 'cannot_')
555
				$this->_error = $this->_sa == 'view' ? 'cannot_view_likes' : 'cannot_like_content';
556
557
			// Is this request coming from an ajax call?
558
			if ($this->_js)
559
			{
560
				$context['sub_template'] = 'generic';
561
				$context['data'] = isset($txt[$this->_error]) ? $txt[$this->_error] : $txt['like_error'];
562
			}
563
564
			// Nope?  then just do a redirect to whatever URL was provided.
565
			else
566
				redirectexit(!empty($this->_validLikes['redirect']) ? $this->_validLikes['redirect'] . ';error=' . $this->_error : '');
567
568
			return;
569
		}
570
571
		// A like operation.
572
		else
573
		{
574
			// Not an ajax request so send the user back to the previous location or the main page.
575
			if (!$this->_js)
576
				redirectexit(!empty($this->_validLikes['redirect']) ? $this->_validLikes['redirect'] : '');
577
578
			// These fine gentlemen all share the same template.
579
			$generic = array('delete', 'insert', '_count');
580
			if (in_array($this->_sa, $generic))
581
			{
582
				$context['sub_template'] = 'generic';
583
				$context['data'] = isset($txt['like_' . $this->_data]) ? $txt['like_' . $this->_data] : $this->_data;
584
			}
585
586
			// Directly pass the current called sub-action and the data generated by its associated Method.
587
			else
588
			{
589
				$context['sub_template'] = $this->_sa;
590
				$context['data'] = $this->_data;
591
			}
592
		}
593
	}
594
595
	/**
596
	 * Outputs a JSON-encoded response
597
	 */
598
	protected function jsonResponse()
599
	{
600
		global $smcFunc;
601
602
		$print = array(
603
			'data' => $this->_data,
604
		);
605
606
		// If there is an error, send it.
607
		if ($this->_error)
608
		{
609
			if ($this->_error == 'cannot_')
610
				$this->_error = $this->_sa == 'view' ? 'cannot_view_likes' : 'cannot_like_content';
611
612
			$print['error'] = $this->_error;
613
		}
614
615
		// Do you want to add something at the very last minute?
616
		call_integration_hook('integrate_likes_json_response', array(&$print));
617
618
		// Print the data.
619
		smf_serverResponse($smcFunc['json_encode']($print));
620
		die;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
621
	}
622
}
623
624
/**
625
 * What's this?  I dunno, what are you talking about?  Never seen this before, nope.  No sir.
626
 */
627
function BookOfUnknown()
628
{
629
	global $context, $scripturl;
630
631
	echo '<!DOCTYPE html>
632
<html', $context['right_to_left'] ? ' dir="rtl"' : '', '>
633
	<head>
634
		<title>The Book of Unknown, ', @$_GET['verse'] == '2:18' ? '2:18' : '4:16', '</title>
635
		<style>
636
			em
637
			{
638
				font-size: 1.3em;
639
				line-height: 0;
640
			}
641
		</style>
642
	</head>
643
	<body style="background-color: #444455; color: white; font-style: italic; font-family: serif;">
644
		<div style="margin-top: 12%; font-size: 1.1em; line-height: 1.4; text-align: center;">';
645
646
	if (!isset($_GET['verse']) || ($_GET['verse'] != '2:18' && $_GET['verse'] != '22:1-2'))
647
		$_GET['verse'] = '4:16';
648
649
	if ($_GET['verse'] == '2:18')
650
		echo '
651
			Woe, it was that his name wasn\'t <em>known</em>, that he came in mystery, and was recognized by none.&nbsp;And it became to be in those days <em>something</em>.&nbsp; Something not yet <em id="unknown" name="[Unknown]">unknown</em> to mankind.&nbsp; And thus what was to be known the <em>secret project</em> began into its existence.&nbsp; Henceforth the opposition was only <em>weary</em> and <em>fearful</em>, for now their match was at arms against them.';
652
	elseif ($_GET['verse'] == '4:16')
653
		echo '
654
			And it came to pass that the <em>unbelievers</em> dwindled in number and saw rise of many <em>proselytizers</em>, and the opposition found fear in the face of the <em>x</em> and the <em>j</em> while those who stood with the <em>something</em> grew stronger and came together.&nbsp; Still, this was only the <em>beginning</em>, and what lay in the future was <em id="unknown" name="[Unknown]">unknown</em> to all, even those on the right side.';
655
	elseif ($_GET['verse'] == '22:1-2')
656
		echo '
657
			<p>Now <em>behold</em>, that which was once the secret project was <em id="unknown" name="[Unknown]">unknown</em> no longer.&nbsp; Alas, it needed more than <em>only one</em>, but yet even thought otherwise.&nbsp; It became that the opposition <em>rumored</em> and lied, but still to no avail.&nbsp; Their match, though not <em>perfect</em>, had them outdone.</p>
658
			<p style="margin: 2ex 1ex 0 1ex; font-size: 1.05em; line-height: 1.5; text-align: center;">Let it continue.&nbsp; <em>The end</em>.</p>';
659
660
	echo '
661
		</div>
662
		<div style="margin-top: 2ex; font-size: 2em; text-align: right;">';
663
664
	if ($_GET['verse'] == '2:18')
665
		echo '
666
			from <span style="font-family: Georgia, serif;"><strong><a href="', $scripturl, '?action=about:unknown;verse=4:16" style="color: white; text-decoration: none; cursor: text;">The Book of Unknown</a></strong>, 2:18</span>';
667
	elseif ($_GET['verse'] == '4:16')
668
		echo '
669
			from <span style="font-family: Georgia, serif;"><strong><a href="', $scripturl, '?action=about:unknown;verse=22:1-2" style="color: white; text-decoration: none; cursor: text;">The Book of Unknown</a></strong>, 4:16</span>';
670
	elseif ($_GET['verse'] == '22:1-2')
671
		echo '
672
			from <span style="font-family: Georgia, serif;"><strong>The Book of Unknown</strong>, 22:1-2</span>';
673
674
	echo '
675
		</div>
676
	</body>
677
</html>';
678
679
	obExit(false);
680
}
681
682
?>