This repository has been archived on 2024-06-26. You can view files and clone it, but cannot push or open issues or pull requests.
sakura/libraries/Utils.php

350 lines
10 KiB
PHP
Raw Normal View History

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;
/**
2016-02-02 21:04:15 +00:00
* Meta utility functions.
2016-03-08 23:07:58 +00:00
*
* @package Sakura
2016-02-02 21:04:15 +00:00
* @author Julian van de Groep <me@flash.moe>
*/
2016-01-17 01:58:31 +00:00
class Utils
{
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.
*/
public static function errorHandler($errno, $errstr, $errfile, $errline)
{
// Remove ROOT path from the error string and file location
$errstr = str_replace(ROOT, '', $errstr);
$errfile = str_replace(ROOT, '', $errfile);
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
. ' 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
// 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; }
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; }
.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;
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; }
.container .footer { border-top: 1px solid #CAA; font-size: x-small; padding: 0 5px 1px; }
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>';
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>';
} 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-12-09 20:21:08 +00:00
if ($detailed) {
$errorPage .= ' <h2>Summary</h2>
<pre class="error">' . $error . '</pre>
<h2>Backtraces</h2>';
2016-02-28 17:45:25 +00:00
foreach (debug_backtrace() as $num => $trace) {
$errorPage .= '<h3>#' . $num . '</h3><pre class="error">';
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";
}
$errorPage .= '</pre>';
}
}
$errorPage .= '</div>
<div class="footer">
Sakura r' . SAKURA_VERSION . '.
</div>
</div>
</body>
</html>';
2015-04-18 18:32:41 +00:00
// Die and display error message
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.
*/
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
$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
foreach ($to as $email => $name) {
$mail->addBCC($email, $name);
}
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
$send = $mail->send();
2015-04-18 18:26:52 +00:00
// Clear the addressee list
$mail->clearAddresses();
2015-04-18 18:26:52 +00:00
// If we got an error return the error
if (!$send) {
2015-04-18 18:26:52 +00:00
return $mail->ErrorInfo;
}
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-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
if ($lower) {
2015-04-01 17:34:36 +00:00
$string = strtolower($string);
}
2015-04-27 00:41:59 +00:00
// If set remove all characters that aren't a-z or 0-9
if ($noSpecial) {
2016-01-04 20:14:09 +00:00
$string = preg_replace('/[^a-z0-9]/', $replaceSpecial, $string);
}
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.
*/
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.
*/
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")) {
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
// 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
if (isset($_SERVER['HTTP_CF_IPCOUNTRY'])) {
2015-04-27 17:04:27 +00:00
return $_SERVER['HTTP_CF_IPCOUNTRY'];
}
// 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.
*/
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.
*/
public static function getCountryName($code)
{
// Catch XX
if (strtolower($code) === 'xx') {
return 'Unknown';
}
// Catch proxy
if (strtolower($code) === 'a1') {
return 'Anonymous Proxy';
}
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.
*/
public static function getByteSymbol($bytes)
{
2015-08-09 18:26:01 +00:00
// Return nothing if the input was 0
if (!$bytes) {
2015-08-09 18:26:01 +00:00
return;
}
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
$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
}