2015-04-01 17:34:36 +00:00
|
|
|
<?php
|
2016-02-03 22:22:56 +00:00
|
|
|
/**
|
|
|
|
* Holds various utility functions.
|
2016-03-08 23:07:58 +00:00
|
|
|
*
|
2016-02-03 22:22:56 +00:00
|
|
|
* @package Sakura
|
|
|
|
*/
|
|
|
|
|
2015-04-01 17:34:36 +00:00
|
|
|
namespace Sakura;
|
|
|
|
|
2015-06-04 12:41:55 +00:00
|
|
|
use PHPMailer;
|
|
|
|
|
2015-10-18 19:06:30 +00:00
|
|
|
/**
|
2016-02-02 21:04:15 +00:00
|
|
|
* Meta utility functions.
|
2016-03-08 23:07:58 +00:00
|
|
|
*
|
2015-10-18 19:06:30 +00:00
|
|
|
* @package Sakura
|
2016-02-02 21:04:15 +00:00
|
|
|
* @author Julian van de Groep <me@flash.moe>
|
2015-10-18 19:06:30 +00:00
|
|
|
*/
|
2016-01-17 01:58:31 +00:00
|
|
|
class Utils
|
2015-09-14 20:51:23 +00:00
|
|
|
{
|
2016-02-02 21:04:15 +00:00
|
|
|
/**
|
|
|
|
* The error handler.
|
2016-03-08 23:07:58 +00:00
|
|
|
*
|
2016-02-02 21:04:15 +00:00
|
|
|
* @param int $errno The error ID.
|
|
|
|
* @param string $errstr Quick description of the event.
|
|
|
|
* @param string $errfile File the error occurred in.
|
|
|
|
* @param int $errline Line the error occurred on.
|
|
|
|
*/
|
2015-09-14 20:51:23 +00:00
|
|
|
public static function errorHandler($errno, $errstr, $errfile, $errline)
|
|
|
|
{
|
2015-09-06 01:04:55 +00:00
|
|
|
// Remove ROOT path from the error string and file location
|
2015-09-14 20:51:23 +00:00
|
|
|
$errstr = str_replace(ROOT, '', $errstr);
|
|
|
|
$errfile = str_replace(ROOT, '', $errfile);
|
2015-09-06 01:04:55 +00:00
|
|
|
|
2015-04-18 18:32:41 +00:00
|
|
|
switch ($errno) {
|
|
|
|
case E_ERROR:
|
|
|
|
case E_USER_ERROR:
|
|
|
|
$error = '<b>FATAL ERROR</b>: ' . $errstr . ' on line ' . $errline . ' in ' . $errfile;
|
2015-04-01 17:34:36 +00:00
|
|
|
break;
|
|
|
|
|
2015-04-18 18:32:41 +00:00
|
|
|
case E_WARNING:
|
|
|
|
case E_USER_WARNING:
|
|
|
|
$error = '<b>WARNING</b>: ' . $errstr . ' on line ' . $errline . ' in ' . $errfile;
|
2015-04-01 17:34:36 +00:00
|
|
|
break;
|
|
|
|
|
2015-04-18 18:32:41 +00:00
|
|
|
case E_NOTICE:
|
|
|
|
case E_USER_NOTICE:
|
|
|
|
$error = '<b>NOTICE</b>: ' . $errstr . ' on line ' . $errline . ' in ' . $errfile;
|
2015-04-01 17:34:36 +00:00
|
|
|
break;
|
|
|
|
|
2015-04-18 18:32:41 +00:00
|
|
|
default:
|
2015-09-14 21:41:43 +00:00
|
|
|
$error = '<b>Unknown error type</b> [' . $errno . ']: ' . $errstr . ' on line ' . $errline
|
2016-03-13 20:35:51 +00:00
|
|
|
. ' in ' . $errfile;
|
2015-04-18 18:32:41 +00:00
|
|
|
}
|
2015-04-01 17:34:36 +00:00
|
|
|
|
2015-04-18 18:32:41 +00:00
|
|
|
// Truncate all previous outputs
|
|
|
|
ob_clean();
|
2015-05-29 19:27:45 +00:00
|
|
|
ob_end_clean();
|
2015-04-01 17:34:36 +00:00
|
|
|
|
2015-12-04 14:19:10 +00:00
|
|
|
// Check for dev mode
|
2015-12-27 04:37:57 +00:00
|
|
|
$detailed = Config::local('dev', 'show_errors');
|
2015-12-04 14:19:10 +00:00
|
|
|
|
2015-09-06 01:04:55 +00:00
|
|
|
// Build page
|
|
|
|
$errorPage = '<!DOCTYPE html>
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<meta charset="utf-8" />
|
|
|
|
<title>Sakura Internal Error</title>
|
|
|
|
<style type="text/css">
|
2015-09-14 21:41:43 +00:00
|
|
|
body { margin: 0; padding: 0; background: #EEE; color: #000;
|
|
|
|
font: 12px/20px Verdana, Arial, Helvetica, sans-serif; }
|
|
|
|
h1, h2 { font-weight: 100; background: #CAA; padding: 8px 5px 10px;
|
|
|
|
margin: 0; font-style: italic; font-family: serif; }
|
2015-09-06 01:04:55 +00:00
|
|
|
h1 { border-radius: 8px 8px 0 0; }
|
|
|
|
h2 { margin: 0 -10px; }
|
2015-09-14 21:41:43 +00:00
|
|
|
.container { border: 1px solid #CAA; margin: 10px auto; background: #FFF;
|
|
|
|
box-shadow: 2px 2px 1em #888; max-width: 1024px; border-radius: 10px; }
|
2015-10-18 19:06:30 +00:00
|
|
|
.container .inner { padding: 0 10px; }
|
2015-09-14 21:41:43 +00:00
|
|
|
.container .inner .error { background: #555; color: #EEE; border-left: 5px solid #C22;
|
2015-10-18 19:06:30 +00:00
|
|
|
padding: 4px 6px; text-shadow: 0 1px 1px #888; white-space: pre-wrap;
|
2015-09-14 21:41:43 +00:00
|
|
|
word-wrap: break-word; margin: 12px 0; border-radius: 5px; box-shadow: inset 0 0 1em #333; }
|
2015-10-18 19:06:30 +00:00
|
|
|
.container .footer { border-top: 1px solid #CAA; font-size: x-small; padding: 0 5px 1px; }
|
2015-09-06 01:04:55 +00:00
|
|
|
a { color: #77E; text-decoration: none; }
|
|
|
|
a:hover { text-decoration: underline; }
|
|
|
|
a:active { color: #E77; }
|
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div class="container">
|
|
|
|
<h1>An error occurred while executing the script.</h1>
|
|
|
|
<div class="inner">
|
|
|
|
<p>To prevent potential security risks or data loss Sakura has stopped execution of the script.</p>';
|
|
|
|
|
2015-09-14 20:51:23 +00:00
|
|
|
if (isset($errid)) {
|
|
|
|
$errorPage .= '<p>The error and surrounding data has been logged.</p>
|
2015-12-09 20:21:08 +00:00
|
|
|
<h2>' . (!$detailed ? 'Report the following text to a staff member' : 'Logged as') . '</h2>
|
2015-09-14 21:41:43 +00:00
|
|
|
<pre class="error">' . $errid . '</pre>';
|
2015-09-14 20:51:23 +00:00
|
|
|
} else {
|
2015-09-14 21:41:43 +00:00
|
|
|
$errorPage .= '<p>Sakura was not able to log this error which could mean that there was an error
|
|
|
|
with the database connection. If you\'re the system administrator check the database credentials
|
|
|
|
and make sure the server is running and if you\'re not please let the system administrator
|
|
|
|
know about this error if it occurs again.</p>';
|
2015-09-14 20:51:23 +00:00
|
|
|
}
|
2015-09-06 01:04:55 +00:00
|
|
|
|
2015-12-09 20:21:08 +00:00
|
|
|
if ($detailed) {
|
2015-09-14 20:51:23 +00:00
|
|
|
$errorPage .= ' <h2>Summary</h2>
|
|
|
|
<pre class="error">' . $error . '</pre>
|
2015-09-06 01:04:55 +00:00
|
|
|
<h2>Backtraces</h2>';
|
|
|
|
|
2016-02-28 17:45:25 +00:00
|
|
|
foreach (debug_backtrace() as $num => $trace) {
|
2015-09-14 20:51:23 +00:00
|
|
|
$errorPage .= '<h3>#' . $num . '</h3><pre class="error">';
|
2015-09-06 01:04:55 +00:00
|
|
|
|
2015-09-14 20:51:23 +00:00
|
|
|
foreach ($trace as $key => $val) {
|
2015-09-14 21:41:43 +00:00
|
|
|
$errorPage .=
|
|
|
|
str_pad(
|
|
|
|
'[' . $key . ']',
|
|
|
|
12
|
|
|
|
) . '=> ' . (
|
|
|
|
is_array($val) || is_object($val) ?
|
|
|
|
json_encode($val) :
|
|
|
|
$val
|
|
|
|
) . "\r\n";
|
2015-09-14 20:51:23 +00:00
|
|
|
}
|
2015-09-06 01:04:55 +00:00
|
|
|
|
2015-09-14 20:51:23 +00:00
|
|
|
$errorPage .= '</pre>';
|
|
|
|
}
|
2015-09-06 01:04:55 +00:00
|
|
|
}
|
|
|
|
|
2015-09-14 20:51:23 +00:00
|
|
|
$errorPage .= '</div>
|
2015-09-06 01:04:55 +00:00
|
|
|
<div class="footer">
|
2015-09-14 20:51:23 +00:00
|
|
|
Sakura r' . SAKURA_VERSION . '.
|
2015-09-06 01:04:55 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</body>
|
|
|
|
</html>';
|
|
|
|
|
2015-04-18 18:32:41 +00:00
|
|
|
// Die and display error message
|
2015-09-06 01:04:55 +00:00
|
|
|
die($errorPage);
|
2015-04-18 18:32:41 +00:00
|
|
|
}
|
2015-04-01 17:34:36 +00:00
|
|
|
|
2016-02-02 21:04:15 +00:00
|
|
|
/**
|
|
|
|
* Send an e-mail.
|
2016-03-08 23:07:58 +00:00
|
|
|
*
|
2016-02-02 21:04:15 +00:00
|
|
|
* @param string $to Destination e-mail.
|
|
|
|
* @param string $subject E-mail subject.
|
|
|
|
* @param string $body Contents of the message.
|
|
|
|
* @return bool|string Return whatever PHPMailer returns.
|
|
|
|
*/
|
2015-09-14 20:51:23 +00:00
|
|
|
public static function sendMail($to, $subject, $body)
|
|
|
|
{
|
2015-04-18 18:26:52 +00:00
|
|
|
// Initialise PHPMailer
|
2015-06-04 12:41:55 +00:00
|
|
|
$mail = new PHPMailer();
|
2015-04-18 18:26:52 +00:00
|
|
|
|
|
|
|
// Set to SMTP
|
2015-10-18 19:06:30 +00:00
|
|
|
$mail->isSMTP();
|
2015-04-18 18:26:52 +00:00
|
|
|
|
|
|
|
// Set the SMTP server host
|
2015-12-04 14:19:10 +00:00
|
|
|
$mail->Host = Config::get('smtp_server');
|
2015-04-18 18:26:52 +00:00
|
|
|
|
|
|
|
// Do we require authentication?
|
2015-12-04 14:19:10 +00:00
|
|
|
$mail->SMTPAuth = Config::get('smtp_auth');
|
2015-04-18 18:26:52 +00:00
|
|
|
|
|
|
|
// Do we encrypt as well?
|
2015-12-04 14:19:10 +00:00
|
|
|
$mail->SMTPSecure = Config::get('smtp_secure');
|
2015-04-18 18:26:52 +00:00
|
|
|
|
|
|
|
// Set the port to the SMTP server
|
2015-12-04 14:19:10 +00:00
|
|
|
$mail->Port = Config::get('smtp_port');
|
2015-04-18 18:26:52 +00:00
|
|
|
|
|
|
|
// If authentication is required log in as well
|
2015-12-04 14:19:10 +00:00
|
|
|
if (Config::get('smtp_auth')) {
|
|
|
|
$mail->Username = Config::get('smtp_username');
|
|
|
|
$mail->Password = base64_decode(Config::get('smtp_password'));
|
2015-04-18 18:26:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add a reply-to header
|
2015-12-04 14:19:10 +00:00
|
|
|
$mail->addReplyTo(Config::get('smtp_replyto_mail'), Config::get('smtp_replyto_name'));
|
2015-04-18 18:26:52 +00:00
|
|
|
|
|
|
|
// Set a from address as well
|
2015-12-04 14:19:10 +00:00
|
|
|
$mail->setFrom(Config::get('smtp_from_email'), Config::get('smtp_from_name'));
|
2015-04-18 18:26:52 +00:00
|
|
|
|
|
|
|
// Set the addressee
|
2015-09-14 20:51:23 +00:00
|
|
|
foreach ($to as $email => $name) {
|
2015-10-18 19:06:30 +00:00
|
|
|
$mail->addBCC($email, $name);
|
2015-09-05 16:11:04 +00:00
|
|
|
}
|
|
|
|
|
2015-04-18 18:26:52 +00:00
|
|
|
// Subject line
|
|
|
|
$mail->Subject = $subject;
|
|
|
|
|
2016-01-20 23:06:21 +00:00
|
|
|
// Set body
|
|
|
|
$mail->Body = $body;
|
2015-04-18 18:26:52 +00:00
|
|
|
|
|
|
|
// Send the message
|
2015-10-18 19:06:30 +00:00
|
|
|
$send = $mail->send();
|
2015-04-18 18:26:52 +00:00
|
|
|
|
|
|
|
// Clear the addressee list
|
2015-10-18 19:06:30 +00:00
|
|
|
$mail->clearAddresses();
|
2015-04-18 18:26:52 +00:00
|
|
|
|
|
|
|
// If we got an error return the error
|
2015-09-14 20:51:23 +00:00
|
|
|
if (!$send) {
|
2015-04-18 18:26:52 +00:00
|
|
|
return $mail->ErrorInfo;
|
2015-09-05 16:11:04 +00:00
|
|
|
}
|
|
|
|
|
2015-04-18 18:26:52 +00:00
|
|
|
// Else just return whatever
|
|
|
|
return $send;
|
|
|
|
}
|
|
|
|
|
2016-02-02 21:04:15 +00:00
|
|
|
/**
|
|
|
|
* Clean a string
|
2016-03-08 23:07:58 +00:00
|
|
|
*
|
2016-02-02 21:04:15 +00:00
|
|
|
* @param string $string Dirty string.
|
|
|
|
* @param bool $lower Make the string lowercase.
|
|
|
|
* @param bool $noSpecial String all special characters.
|
|
|
|
* @param bool $replaceSpecial Thing to replace special characters with.
|
2016-03-08 23:07:58 +00:00
|
|
|
*
|
2016-02-02 21:04:15 +00:00
|
|
|
* @return string Clean string.
|
|
|
|
*/
|
2016-01-04 20:14:09 +00:00
|
|
|
public static function cleanString($string, $lower = false, $noSpecial = false, $replaceSpecial = '')
|
2015-09-14 20:51:23 +00:00
|
|
|
{
|
2015-04-27 00:41:59 +00:00
|
|
|
// Run common sanitisation function over string
|
2015-12-04 14:19:10 +00:00
|
|
|
$string = htmlentities($string, ENT_NOQUOTES | ENT_HTML401, Config::get('charset'));
|
2015-04-18 18:32:41 +00:00
|
|
|
$string = stripslashes($string);
|
|
|
|
$string = strip_tags($string);
|
2015-04-27 00:41:59 +00:00
|
|
|
|
|
|
|
// If set also make the string lowercase
|
2015-09-14 20:51:23 +00:00
|
|
|
if ($lower) {
|
2015-04-01 17:34:36 +00:00
|
|
|
$string = strtolower($string);
|
2015-09-05 16:11:04 +00:00
|
|
|
}
|
|
|
|
|
2015-04-27 00:41:59 +00:00
|
|
|
// If set remove all characters that aren't a-z or 0-9
|
2015-09-14 20:51:23 +00:00
|
|
|
if ($noSpecial) {
|
2016-01-04 20:14:09 +00:00
|
|
|
$string = preg_replace('/[^a-z0-9]/', $replaceSpecial, $string);
|
2015-09-05 16:11:04 +00:00
|
|
|
}
|
|
|
|
|
2015-04-27 00:41:59 +00:00
|
|
|
// Return clean string
|
2015-04-18 18:32:41 +00:00
|
|
|
return $string;
|
2015-04-01 17:34:36 +00:00
|
|
|
}
|
|
|
|
|
2016-02-02 21:04:15 +00:00
|
|
|
/**
|
|
|
|
* Validate MX records.
|
2016-03-08 23:07:58 +00:00
|
|
|
*
|
2016-02-02 21:04:15 +00:00
|
|
|
* @param string $email E-mail address.
|
2016-03-08 23:07:58 +00:00
|
|
|
*
|
2016-02-02 21:04:15 +00:00
|
|
|
* @return bool Success.
|
|
|
|
*/
|
2015-09-14 20:51:23 +00:00
|
|
|
public static function checkMXRecord($email)
|
|
|
|
{
|
2015-04-19 13:00:32 +00:00
|
|
|
// Get the domain from the e-mail address
|
|
|
|
$domain = substr(strstr($email, '@'), 1);
|
2015-04-14 14:27:37 +00:00
|
|
|
|
|
|
|
// Check the MX record
|
|
|
|
$record = checkdnsrr($domain, 'MX');
|
|
|
|
|
|
|
|
// Return the record data
|
|
|
|
return $record;
|
|
|
|
}
|
|
|
|
|
2016-02-02 21:04:15 +00:00
|
|
|
/**
|
|
|
|
* Get the country code of a visitor.
|
2016-03-08 23:07:58 +00:00
|
|
|
*
|
2016-02-02 21:04:15 +00:00
|
|
|
* @return string 2 character country code.
|
|
|
|
*/
|
2015-09-14 20:51:23 +00:00
|
|
|
public static function getCountryCode()
|
|
|
|
{
|
2015-11-20 12:15:40 +00:00
|
|
|
// Attempt to get country code using PHP's built in geo thing
|
|
|
|
if (function_exists("geoip_country_code_by_name")) {
|
2016-03-13 20:53:02 +00:00
|
|
|
try {
|
2016-03-27 21:18:57 +00:00
|
|
|
$code = geoip_country_code_by_name(Net::ip());
|
2016-02-02 21:04:15 +00:00
|
|
|
|
2016-03-13 20:53:02 +00:00
|
|
|
// Check if $code is anything
|
|
|
|
if ($code) {
|
|
|
|
return $code;
|
|
|
|
}
|
|
|
|
} catch (\Exception $e) {
|
2015-11-20 12:15:40 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-18 18:26:52 +00:00
|
|
|
|
2015-04-27 17:04:27 +00:00
|
|
|
// Check if the required header is set and return it
|
2015-09-14 20:51:23 +00:00
|
|
|
if (isset($_SERVER['HTTP_CF_IPCOUNTRY'])) {
|
2015-04-27 17:04:27 +00:00
|
|
|
return $_SERVER['HTTP_CF_IPCOUNTRY'];
|
2015-09-05 16:11:04 +00:00
|
|
|
}
|
|
|
|
|
2015-09-03 19:44:14 +00:00
|
|
|
// Return XX as a fallback
|
|
|
|
return 'XX';
|
2015-04-18 18:26:52 +00:00
|
|
|
}
|
|
|
|
|
2016-02-02 21:04:15 +00:00
|
|
|
/**
|
|
|
|
* Check the entropy of a password.
|
2016-03-08 23:07:58 +00:00
|
|
|
*
|
2016-02-02 21:04:15 +00:00
|
|
|
* @param string $pw Password.
|
2016-03-08 23:07:58 +00:00
|
|
|
*
|
2016-02-02 21:04:15 +00:00
|
|
|
* @return double|int Entropy.
|
|
|
|
*/
|
2015-09-14 20:51:23 +00:00
|
|
|
public static function pwdEntropy($pw)
|
|
|
|
{
|
2015-04-24 17:48:56 +00:00
|
|
|
// Decode utf-8 chars
|
|
|
|
$pw = utf8_decode($pw);
|
|
|
|
|
|
|
|
// Count the amount of unique characters in the password string and calculate the entropy
|
|
|
|
return count(count_chars($pw, 1)) * log(256, 2);
|
|
|
|
}
|
|
|
|
|
2016-02-02 21:04:15 +00:00
|
|
|
/**
|
|
|
|
* Get the country name from a 2 character code.
|
2016-03-08 23:07:58 +00:00
|
|
|
*
|
2016-02-02 21:04:15 +00:00
|
|
|
* @param string $code The country code.
|
2016-03-08 23:07:58 +00:00
|
|
|
*
|
2016-02-02 21:04:15 +00:00
|
|
|
* @return string The country name.
|
|
|
|
*/
|
2015-09-14 20:51:23 +00:00
|
|
|
public static function getCountryName($code)
|
|
|
|
{
|
2016-03-13 20:53:02 +00:00
|
|
|
// Catch XX
|
|
|
|
if (strtolower($code) === 'xx') {
|
|
|
|
return 'Unknown';
|
|
|
|
}
|
|
|
|
|
|
|
|
// Catch proxy
|
|
|
|
if (strtolower($code) === 'a1') {
|
|
|
|
return 'Anonymous Proxy';
|
2015-09-05 16:11:04 +00:00
|
|
|
}
|
|
|
|
|
2016-03-13 20:53:02 +00:00
|
|
|
return locale_get_display_region("-{$code}", 'en');
|
2015-04-27 00:41:59 +00:00
|
|
|
}
|
|
|
|
|
2016-02-02 21:04:15 +00:00
|
|
|
/**
|
|
|
|
* Get the byte symbol for a unit from bytes.
|
2016-03-08 23:07:58 +00:00
|
|
|
*
|
2016-02-02 21:04:15 +00:00
|
|
|
* @param int $bytes The amount of bytes.
|
2016-03-08 23:07:58 +00:00
|
|
|
*
|
2016-02-02 21:04:15 +00:00
|
|
|
* @return string The converted amount with the symbol.
|
|
|
|
*/
|
2015-09-14 20:51:23 +00:00
|
|
|
public static function getByteSymbol($bytes)
|
|
|
|
{
|
2015-08-09 18:26:01 +00:00
|
|
|
// Return nothing if the input was 0
|
2015-09-14 20:51:23 +00:00
|
|
|
if (!$bytes) {
|
2015-08-09 18:26:01 +00:00
|
|
|
return;
|
2015-09-14 20:51:23 +00:00
|
|
|
}
|
2015-08-09 18:26:01 +00:00
|
|
|
|
|
|
|
// Array with byte symbols
|
|
|
|
$symbols = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
|
|
|
|
|
|
|
|
// Calculate byte entity
|
|
|
|
$exp = floor(log($bytes) / log(1024));
|
|
|
|
|
|
|
|
// Format the things
|
2015-09-14 20:51:23 +00:00
|
|
|
$bytes = sprintf("%.2f " . $symbols[$exp], ($bytes / pow(1024, floor($exp))));
|
2015-08-09 18:26:01 +00:00
|
|
|
|
|
|
|
// Return the formatted string
|
|
|
|
return $bytes;
|
|
|
|
}
|
2015-04-01 17:34:36 +00:00
|
|
|
}
|