<?php namespace HashOver;// Copyright (C) 2010-2021 Jacob Barkdull// This file is part of HashOver.//// HashOver is free software: you can redistribute it and/or modify// it under the terms of the GNU Affero General Public License as// published by the Free Software Foundation, either version 3 of the// License, or (at your option) any later version.//// HashOver is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU Affero General Public License for more details.//// You should have received a copy of the GNU Affero General Public License// along with HashOver.  If not, see <http://www.gnu.org/licenses/>.// Parse comments and create deleted comment noteclass CommentParser{	protected $setup;	protected $login;	protected $cookies;	protected $locale;	protected $avatars;	protected $timeModify;	protected $currentDate;	protected $shortDateLocales;	protected $todayLocale;	protected $date;	protected $time;	public function __construct (Setup $setup)	{		// Store parameters as properties		$this->setup = $setup;		// Instantiate various classes		$this->login = new Login ($setup);		$this->cookies = new Cookies ($setup, $this->login);		$this->locale = new Locale ($setup);		$this->avatars = new Avatars ($setup);		// Get current time		$current_time = new \DateTime ();		// Get 24-hour time from client		$client_time = new \DateTime ($setup->getRequest ('time'));		// Server-side hours and minutes as integers		$current_hours = (int)($current_time->format ('H'));		$current_mins = (int)($current_time->format ('i'));		// Client hours and minutes as integers		$client_hours = (int)($client_time->format ('H'));		$client_mins = (int)($client_time->format ('i'));		// Hours and minutes to adjust posting time by		$this->timeModify = sprintf (			'%+d hours %+d minutes',			$client_hours - $current_hours,			$client_mins - $current_mins		);		// Get current date without time		$this->currentDate = new \DateTime (date ('Y-m-d'));		// Known short date interval locales		$this->shortDateLocales = array (			'y' => 'date-year',			'm' => 'date-month',			'd' => 'date-day'		);		// Short date when a comment was posted today		$this->todayLocale = $this->locale->text['date-today'];		// Check if we have Intl extentsion		if ($setup->hasIntl === true) {			// If so, get date formatter for comment post date			$this->date = $this->getDateFormatter ($setup->datePattern);			// And get date formatter for comment post time			$this->time = $this->getDateFormatter ($setup->timePattern);		}	}	// Get date and time formatter	protected function getDateFormatter ($pattern)	{		// Instantiate International Date Formatter		return \IntlDateFormatter::create (			// Set language as configured			$this->setup->language,			// We're setting our own format			\IntlDateFormatter::NONE,			\IntlDateFormatter::NONE,			// Set timezone as configured			$this->setup->serverTimezone,			// Use Gregorian calender			\IntlDateFormatter::GREGORIAN,			// Set date format			$pattern		);	}	// Get short form date and time	protected function getDateTime (\DateTime $dt, $time)	{		// Remove time from datetime		$datetime = new \DateTime ($dt->format ('Y-m-d'));		// Get difference between today's date and timeless date		$interval = $datetime->diff ($this->currentDate);		// Attempt to get a day, month, or year interval		foreach ($this->shortDateLocales as $i => $key) {			// Skip intervals that are zero			if ($interval->$i <= 0) {				continue;			}			// Otherwise, check if interval is more than one			if ($interval->$i !== 1) {				// If so, use plural locale string				$locale = $this->locale->text[$key . 's'];			} else {				// If not, use singlur locale string				$locale = $this->locale->text[$key];			}			// Inject interval into locale string			$date = sprintf ($locale, $interval->$i);			// And return short date			return $date;		}		// Otherwise, inject time into today locale string		$date = sprintf ($this->todayLocale, $time);		// And return today locale string		return $date;	}	// Parse comment files	public function parse (array $comment, $key, $key_parts, $popular = false)	{		// Initial parsed comment data output		$output = array ();		// Get post date as-is		$date = Misc::getArrayItem ($comment, 'date');		// Get comment post datetime		$post_date = new \DateTime ($date ?: date ('Y-m-d', 0));		// Adjust post date to client timezone if enabled		if ($this->setup->usesUserTimezone === true) {			$post_date->modify ($this->timeModify);		}		// Generate permalink		if (count ($key_parts) > 1) {			$output['permalink'] = 'c' . str_replace ('-', 'r', $key);		} else {			$output['permalink'] = 'c' . $key;		}		// Append "-pop" to end of permalink if popular comment		if ($popular === true) {			$output['permalink'] .= '-pop';		}		// Add name to output		if (!empty ($comment['name'])) {			$output['name'] = $comment['name'];		}		// Add IP address to output if user is admin		if ($this->login->userIsAdmin === true) {			if (!empty ($comment['ipaddr'])) {				$output['ipaddr'] = $comment['ipaddr'];			}		}		// Check if icons are enabled		if ($this->setup->iconMode !== 'none') {			// If so, check if icons are images			if ($this->setup->iconMode === 'image') {				// If so, get MD5 hash for Gravatar from comment				$hash = Misc::getArrayItem ($comment, 'email_hash') ?: '';				// Add Gravatar URL to output				$output['avatar'] = $this->avatars->getGravatar ($hash);			} else {				// If not, use comment permalink number				$output['avatar'] = end ($key_parts);			}		}		// Add website URL to output		if (!empty ($comment['website'])) {			$output['website'] = $comment['website'];		}		// Output whether commenter receives notifications		if (!empty ($comment['email']) and !empty ($comment['notifications'])) {			if ($comment['notifications'] === 'yes') {				$output['subscribed'] = true;			}		}		// Add number of likes to output		if (!empty ($comment['likes'])) {			$output['likes'] = (int)($comment['likes']);		}		// If enabled, add number of dislikes to output		if ($this->setup->allowsDislikes === true) {			if (!empty ($comment['dislikes'])) {				$output['dislikes'] = (int)($comment['dislikes']);			}		}		// Check if the user is logged in		if ($this->login->userIsLoggedIn === true and !empty ($comment['login_id'])) {			// If so, check if this comment belongs to logged in user			if ($this->login->loginHash === $comment['login_id']) {				// If so, set user comment indictor to true				$output['user-owned'] = true;				// And set editable indictor if comment has a password				if (!empty ($comment['password'])) {					$output['editable'] = true;				}			}		}		// Admin is allowed to edit every comment		if ($this->login->userIsAdmin === true) {			$output['editable'] = true;		}		// Create like cookie hash		$like_hash = md5 ($this->setup->domain . $this->setup->threadName . '/' . $key);		// Get like cookie		$like_cookie = $this->cookies->getValue ($like_hash);		// Set liked/disliked indictor		switch ($like_cookie) {			// Comment was liked			case 'liked': {				$output['liked'] = true;				break;			}			// Comment was disliked			case 'disliked': {				// Only set indictor if disliked are enabled				if ($this->setup->allowsDislikes === true) {					$output['disliked'] = true;				}				break;			}		}		// Get micro time of comment post date		$timestamp = $post_date->getTimestamp ();		// Check if we have Intl extentsion		if ($this->setup->hasIntl === true) {			// If so, get localized full comment post date			$full_date = $this->date->format ($timestamp);			// And get localized full comment post time			$post_time = $this->time->format ($timestamp);		} else {			// If not, get default full comment post date			$full_date = $post_date->format ($this->setup->dateFormat);			// And get default full comment post time			$post_time = $post_date->format ($this->setup->timeFormat);		}		// Check if short dates are enabled		if ($this->setup->usesShortDates === true) {			// If so, get localized short date			$comment_date = $this->getDateTime ($post_date, $post_time);		} else {			// If not, use full localized date and time			$comment_date = $full_date;		}		// Check if we have a status		if (!empty ($comment['status'])) {			// If so, get comment status			$status = $comment['status'];			// Check if comment has a status other than approved			if ($status !== 'approved') {				// If so, add comment status to output				$output['status'] = (string)($status);				// Get status locale				$status_locale = $this->locale->text[$status . '-name'];				// And add status text to output				$output['status-text'] = mb_strtolower ($status_locale);			}		}		// Add comment date to output		$output['date'] = $comment_date;		// Set full date and time		$output['date-time'] = $full_date . ' - ' . $post_time;		// Add comment date as Unix timestamp to output		$output['timestamp'] = $timestamp;		// Add comment body to output		$output['body'] = $comment['body'];		// And return parsed comment data		return $output;	}	// Function for adding notices to output	public function notice ($type, $key, &$last_date)	{		// Initial notice data output		$output = array ();		// Set notice name as comment title		$output['title'] = $this->locale->text[$type . '-name'];		// Increase fallback last comment date		$last_date++;		// Add notice icon if icons are enabled		if ($this->setup->iconMode !== 'none') {			$output['avatar'] = $this->setup->getImagePath ($type . '-icon');		}		// Add notice permalink to notice data		$output['permalink'] = 'c' . str_replace ('-', 'r', $key);		// Add notice text to notice data		$output['notice'] = $this->locale->text[$type . '-note'];		// Add notice class to notice data		$output['notice-class'] = 'hashover-' . $type;		// Add last comment date as notice timestamp		$output['timestamp'] = (int)($last_date);		// And return notice data		return $output;	}}