. class Misc { // Allowed JavaScript constructors protected static $objects = array ( 'HashOver', 'HashOverCountLink', 'HashOverLatest' ); // XSS-unsafe characters to search for protected static $searchXSS = array ( '&', '<', '>', '"', "'", '/', '\\' ); // XSS-safe replacement character entities protected static $replaceXSS = array ( '&', '<', '>', '"', ''', '/', '\' ); // Return JSON or JSONP function call public static function jsonData ($data, $self_error = false) { // Encode JSON data $json = json_encode ($data); // Return JSON as-is if the request isn't for JSONP if (!isset ($_GET['jsonp']) or !isset ($_GET['jsonp_object'])) { return $json; } // Otherwise, make JSONP callback index XSS safe $index = self::makeXSSsafe ($_GET['jsonp']); // Make JSONP object constructor name XSS safe $object = self::makeXSSsafe ($_GET['jsonp_object']); // Check if constructor is allowed, if not use default $allowed_object = in_array ($object, self::$objects, true); $object = $allowed_object ? $object : 'HashOver'; // Check if the JSONP index contains a numeric value if (is_numeric ($index) or $self_error === true) { // If so, cast index to positive integer $index = ($self_error === true) ? 0 : (int)(abs ($index)); // Construct JSONP function call $jsonp = sprintf ('%s.jsonp[%d] (%s);', $object, $index, $json); // And return the JSONP script return $jsonp; } // Otherwise, return an error return self::jsonData (array ( 'message' => 'JSONP index must have a numeric value.', 'type' => 'error' ), true); } // Makes a string XSS-safe by removing harmful characters public static function makeXSSsafe ($string) { return str_replace (self::$searchXSS, self::$replaceXSS, $string); } // Returns error in HTML paragraph public static function displayError ($error = 'Something went wrong!', $mode = 'php') { // Initial error message data $data = array (); // Make error message XSS safe $xss_safe = self::makeXSSsafe ($error); // Treat JSONP as JavaScript if ($mode === 'json' and isset ($_GET['jsonp'])) { $mode = 'javascript'; } // Decide how to display error switch ($mode) { // Minimal JavaScript to display error message on page case 'javascript': { $data[] = 'var hashover = document.getElementById (\'hashover\') || document.body;'; $data[] = 'var error = \'

HashOver: ' . $xss_safe . '

\';' . PHP_EOL; $data[] = 'hashover.innerHTML += error;'; break; } // RSS XML to indicate error case 'rss': { $data[] = ''; $data[] = 'HashOver: ' . $xss_safe . ''; break; } // JSON to indicate error case 'json': { $data[] = self::jsonData (array ( 'message' => $error, 'type' => 'error' )); break; } // Default just return the error message default: { $data[] = '

HashOver: ' . $error . '

'; break; } } // Convert error message data to string $message = implode (PHP_EOL, $data); return $message; } // Returns error in HTML paragraph public static function displayException (\Exception $error, $mode = 'php') { return self::displayError ($error->getMessage (), $mode); } // Returns an array item or a given default value public static function getArrayItem (array $data, $key) { return !empty ($data[$key]) ? $data[$key] : false; } }