add chat components
This commit is contained in:
parent
0493e3dcbb
commit
65740718fb
12 changed files with 620 additions and 9 deletions
17
app/Chat/AuthInterface.php
Normal file
17
app/Chat/AuthInterface.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* Holds the authentication interface.
|
||||
* @package Sakura
|
||||
*/
|
||||
|
||||
namespace Sakura\Chat;
|
||||
|
||||
/**
|
||||
* Interface for authentication methods.
|
||||
* @package Sakura
|
||||
* @author Julian van de Groep <me@flash.moe>
|
||||
*/
|
||||
interface AuthInterface
|
||||
{
|
||||
public function attempt();
|
||||
}
|
81
app/Chat/LinkInfo.php
Normal file
81
app/Chat/LinkInfo.php
Normal file
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
/**
|
||||
* Holds the link info object.
|
||||
* @package Sakura
|
||||
*/
|
||||
|
||||
namespace Sakura\Chat;
|
||||
|
||||
/**
|
||||
* Object to serve back to the chat.
|
||||
* @package Sakura
|
||||
* @author Julian van de Groep <me@flash.moe>
|
||||
*/
|
||||
class LinkInfo
|
||||
{
|
||||
/**
|
||||
* Types for $Type.
|
||||
*/
|
||||
const TYPES = [
|
||||
'PLAIN' => 0,
|
||||
'META' => 1,
|
||||
'VIDEO' => 2,
|
||||
'AUDIO' => 3,
|
||||
'IMAGE' => 4,
|
||||
'EMBED' => 5,
|
||||
];
|
||||
|
||||
/**
|
||||
* Modifiable url.
|
||||
* @var string
|
||||
*/
|
||||
public $URL;
|
||||
|
||||
/**
|
||||
* Original url.
|
||||
* @var string
|
||||
*/
|
||||
public $OriginalURL;
|
||||
|
||||
/**
|
||||
* Type (from const TYPES).
|
||||
* @var int
|
||||
*/
|
||||
public $Type;
|
||||
|
||||
/**
|
||||
* Full image or thumbnail, depends on Type.
|
||||
* @var string
|
||||
*/
|
||||
public $Image;
|
||||
|
||||
/**
|
||||
* Title/header text.
|
||||
* @var string
|
||||
*/
|
||||
public $Title;
|
||||
|
||||
/**
|
||||
* Description text.
|
||||
* @var string
|
||||
*/
|
||||
public $Description;
|
||||
|
||||
/**
|
||||
* The content type to assign if applicable.
|
||||
* @var string
|
||||
*/
|
||||
public $ContentType;
|
||||
|
||||
/**
|
||||
* The width of an image if applicable.
|
||||
* @var int
|
||||
*/
|
||||
public $Width;
|
||||
|
||||
/**
|
||||
* The height of an image if applicable.
|
||||
* @var int
|
||||
*/
|
||||
public $Height;
|
||||
}
|
289
app/Chat/Settings.php
Normal file
289
app/Chat/Settings.php
Normal file
|
@ -0,0 +1,289 @@
|
|||
<?php
|
||||
/**
|
||||
* Hold the Sakurako settings object.
|
||||
* @package Sakura
|
||||
*/
|
||||
|
||||
namespace Sakura\Chat;
|
||||
|
||||
/**
|
||||
* Chat settings. Keep this up-to-date with settings.json for Sakurako.
|
||||
* @package Sakura
|
||||
* @author Julian van de Groep <me@flash.moe>
|
||||
*/
|
||||
class Settings
|
||||
{
|
||||
/**
|
||||
* Protocol the chat will use.
|
||||
* @var string
|
||||
*/
|
||||
public $protocol = 'TestRepeater';
|
||||
|
||||
/**
|
||||
* Server address the chat will connect to.
|
||||
* @var string
|
||||
*/
|
||||
public $server = null;
|
||||
|
||||
/**
|
||||
* Title to display on the window/tab.
|
||||
* @var string
|
||||
*/
|
||||
public $title = 'Sakurako';
|
||||
|
||||
/**
|
||||
* Location to redirect to when the authentication failed.
|
||||
* @var string
|
||||
*/
|
||||
public $authRedir = null;
|
||||
|
||||
/**
|
||||
* Cookies to send to the server for authentication (in proper order).
|
||||
* @var array
|
||||
*/
|
||||
public $authCookies = [];
|
||||
|
||||
/**
|
||||
* URL format for avatars, {0} gets replaced with the user's id and set to null to disable.
|
||||
* @var string
|
||||
*/
|
||||
public $avatarUrl = null;
|
||||
|
||||
/**
|
||||
* URL format for profile links, works the same as avatars.
|
||||
* @var string
|
||||
*/
|
||||
public $profileUrl = null;
|
||||
|
||||
/**
|
||||
* Enabling compact (classic) by default.
|
||||
* @var bool
|
||||
*/
|
||||
public $compactView = false;
|
||||
|
||||
/**
|
||||
* Strobe the tab title on new message.
|
||||
* @var bool
|
||||
*/
|
||||
public $flashTitle = true;
|
||||
|
||||
/**
|
||||
* Enabling browser notifications.
|
||||
* @var bool
|
||||
*/
|
||||
public $enableNotifications = true;
|
||||
|
||||
/**
|
||||
* Words that trigger a notification separated with spaces.
|
||||
* @var string
|
||||
*/
|
||||
public $notificationTriggers = '';
|
||||
|
||||
/**
|
||||
* Show the contents of the message in the notification.
|
||||
* @var bool
|
||||
*/
|
||||
public $notificationShowMessage = false;
|
||||
|
||||
/**
|
||||
* Enabling development mode (e.g. loading eruda).
|
||||
* @var bool
|
||||
*/
|
||||
public $development = false;
|
||||
|
||||
/**
|
||||
* Default style.
|
||||
* @var string
|
||||
*/
|
||||
public $style = 'dark';
|
||||
|
||||
/**
|
||||
* Path to language files relative to the chat client's index.
|
||||
* @var string
|
||||
*/
|
||||
public $languagePath = './languages/';
|
||||
|
||||
/**
|
||||
* Default language file to use.
|
||||
* @var string
|
||||
*/
|
||||
public $language = 'en-gb';
|
||||
|
||||
/**
|
||||
* Available languages.
|
||||
* @var array
|
||||
*/
|
||||
public $languages = [
|
||||
'en-gb' => 'English',
|
||||
];
|
||||
|
||||
/**
|
||||
* Formatting string to the timestamp, uses the PHP syntax.
|
||||
* @var string
|
||||
*/
|
||||
public $dateTimeFormat = 'H:i:s';
|
||||
|
||||
/**
|
||||
* Markup parser to use.
|
||||
* @var string
|
||||
*/
|
||||
public $parser = 'WaterDown';
|
||||
|
||||
/**
|
||||
* Enabling the markup parser.
|
||||
* @var bool
|
||||
*/
|
||||
public $enableParser = true;
|
||||
|
||||
/**
|
||||
* Enabling emoticon parsing.
|
||||
* @var bool
|
||||
*/
|
||||
public $enableEmoticons = true;
|
||||
|
||||
/**
|
||||
* Whether urls should be automatically detected in message.
|
||||
* @var bool
|
||||
*/
|
||||
public $autoParseUrls = true;
|
||||
|
||||
/**
|
||||
* Whether the chat should embed url macros like image embedding.
|
||||
* @var bool
|
||||
*/
|
||||
public $autoEmbed = true;
|
||||
|
||||
/**
|
||||
* Enabling automatically scrolling down when a new message is received.
|
||||
* @var bool
|
||||
*/
|
||||
public $autoScroll = true;
|
||||
|
||||
/**
|
||||
* Enabling notification sounds.
|
||||
* @var bool
|
||||
*/
|
||||
public $soundEnable = true;
|
||||
|
||||
/**
|
||||
* The volume percentage for sounds.
|
||||
* @var int
|
||||
*/
|
||||
public $soundVolume = 80;
|
||||
|
||||
/**
|
||||
* The default sound pack.
|
||||
* @var string
|
||||
*/
|
||||
public $soundPack = 'default';
|
||||
|
||||
/**
|
||||
* Available sound packs.
|
||||
* @var array
|
||||
*/
|
||||
public $soundPacks = [
|
||||
'default' => 'Default',
|
||||
];
|
||||
|
||||
/**
|
||||
* Enabling the user join sound.
|
||||
* @var bool
|
||||
*/
|
||||
public $soundEnableJoin = true;
|
||||
|
||||
/**
|
||||
* Enabling the user leave sound.
|
||||
* @var bool
|
||||
*/
|
||||
public $soundEnableLeave = true;
|
||||
|
||||
/**
|
||||
* Enabling the error sound.
|
||||
* @var bool
|
||||
*/
|
||||
public $soundEnableError = true;
|
||||
|
||||
/**
|
||||
* Enabling the server broadcast sound.
|
||||
* @var bool
|
||||
*/
|
||||
public $soundEnableServer = true;
|
||||
|
||||
/**
|
||||
* Enabling the incoming message sound.
|
||||
* @var bool
|
||||
*/
|
||||
public $soundEnableIncoming = true;
|
||||
|
||||
/**
|
||||
* Enabling the outgoing message sound.
|
||||
* @var bool
|
||||
*/
|
||||
public $soundEnableOutgoing = true;
|
||||
|
||||
/**
|
||||
* Enabling the private message sound.
|
||||
* @var bool
|
||||
*/
|
||||
public $soundEnablePrivate = true;
|
||||
|
||||
/**
|
||||
* Enabling the forceful leave (kick/ban/etc) sound.
|
||||
* @var bool
|
||||
*/
|
||||
public $soundEnableForceLeave = true;
|
||||
|
||||
/**
|
||||
* Whether to let the user confirm before closing the tab.
|
||||
* @var bool
|
||||
*/
|
||||
public $closeTabConfirm = false;
|
||||
|
||||
/**
|
||||
* Emoticons to be loaded.
|
||||
* @var array
|
||||
*/
|
||||
public $emoticons = [];
|
||||
|
||||
/**
|
||||
* Applies settings based on Sakura's configuration.
|
||||
*/
|
||||
public function loadStandard()
|
||||
{
|
||||
$this->protocol = config('chat.protocol');
|
||||
$this->server = config('chat.server');
|
||||
$this->title = config('chat.title');
|
||||
$this->authRedir = route('auth.login', null, true);
|
||||
$cpfx = config('cookie.prefix');
|
||||
$this->authCookies = [
|
||||
"{$cpfx}id",
|
||||
"{$cpfx}session",
|
||||
];
|
||||
$this->avatarUrl = route('file.avatar', '{0}', true);
|
||||
$this->profileUrl = route('user.profile', '{0}', true);
|
||||
$this->development = config('dev.show_errors');
|
||||
$this->languagePath = config('chat.language_path');
|
||||
$this->language = config('chat.language');
|
||||
$this->languages = config('chat.languages');
|
||||
$this->dateTimeFormat = config('chat.date_format');
|
||||
$this->parser = config('chat.parser');
|
||||
$this->soundPack = config('chat.sound_pack');
|
||||
$this->soundPacks = config('chat.sound_packs');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding an emoticon to the list.
|
||||
* @param array $triggers
|
||||
* @param string $image
|
||||
* @param int $hierarchy
|
||||
* @param bool $relativePath
|
||||
*/
|
||||
public function addEmoticon($triggers, $image, $hierarchy = 0, $relativePath = false)
|
||||
{
|
||||
$this->emoticons[] = [
|
||||
'Text' => $triggers,
|
||||
'Image' => ($relativePath ? full_domain() : '') . $image,
|
||||
'Hierarchy' => $hierarchy,
|
||||
];
|
||||
}
|
||||
}
|
36
app/Chat/URLResolver.php
Normal file
36
app/Chat/URLResolver.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
/**
|
||||
* Holds the url resolver.
|
||||
* @package Sakura
|
||||
*/
|
||||
|
||||
namespace Sakura\Chat;
|
||||
|
||||
/**
|
||||
* Resolves URL data.
|
||||
* @package Sakura
|
||||
* @author Julian van de Groep <me@flash.moe>
|
||||
*/
|
||||
class URLResolver
|
||||
{
|
||||
/**
|
||||
* Resolves a url.
|
||||
* @param string $protocol
|
||||
* @param string $slashes
|
||||
* @param string $authority
|
||||
* @param string $host
|
||||
* @param string $port
|
||||
* @param string $path
|
||||
* @param string $query
|
||||
* @param string $hash
|
||||
* @return LinkInfo
|
||||
*/
|
||||
public static function resolve($protocol, $slashes, $authority, $host, $port, $path, $query, $hash)
|
||||
{
|
||||
$url = "{$protocol}:{$slashes}{$authority}{$host}{$port}{$path}{$query}{$hash}";
|
||||
$info = new LinkInfo;
|
||||
$info->URL = $info->OriginalURL = $url;
|
||||
$info->Type = LinkInfo::TYPES['PLAIN'];
|
||||
return $info;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,16 @@
|
|||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use Sakura\Chat\LinkInfo;
|
||||
use Sakura\Chat\Settings;
|
||||
use Sakura\Chat\URLResolver;
|
||||
use Sakura\DB;
|
||||
use Sakura\Perms;
|
||||
use Sakura\Perms\Manage;
|
||||
use Sakura\Perms\Site;
|
||||
use Sakura\Session;
|
||||
use Sakura\User;
|
||||
|
||||
/**
|
||||
* Chat related controller.
|
||||
* @package Sakura
|
||||
|
@ -13,12 +23,20 @@ namespace Sakura\Controllers;
|
|||
*/
|
||||
class ChatController extends Controller
|
||||
{
|
||||
/**
|
||||
* Middlewares!
|
||||
* @var array
|
||||
*/
|
||||
protected $middleware = [
|
||||
'EnableCORS',
|
||||
];
|
||||
|
||||
/**
|
||||
* Redirects the user to the chat client.
|
||||
*/
|
||||
public function redirect()
|
||||
{
|
||||
return;
|
||||
header('Location: ' . config('chat.webclient'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,7 +44,78 @@ class ChatController extends Controller
|
|||
* @return string
|
||||
*/
|
||||
public function settings()
|
||||
{
|
||||
$settings = new Settings;
|
||||
$settings->loadStandard();
|
||||
|
||||
$emotes = DB::table('emoticons')
|
||||
->get();
|
||||
|
||||
foreach ($emotes as $emote) {
|
||||
$settings->addEmoticon([$emote->emote_string], $emote->emote_path, 1, true);
|
||||
}
|
||||
|
||||
return $this->json($settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves urls.
|
||||
* @return string
|
||||
*/
|
||||
public function resolve()
|
||||
{
|
||||
$data = json_decode(file_get_contents('php://input'));
|
||||
$info = new LinkInfo;
|
||||
|
||||
if (json_last_error() === JSON_ERROR_NONE) {
|
||||
$info = URLResolver::resolve(
|
||||
$data->Protocol ?? null,
|
||||
$data->Slashes ?? null,
|
||||
$data->Authority ?? null,
|
||||
$data->Host ?? null,
|
||||
$data->Port ?? null,
|
||||
$data->Path ?? null,
|
||||
$data->Query ?? null,
|
||||
$data->Hash ?? null
|
||||
);
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the authentication for a chat server.
|
||||
* @return string
|
||||
*/
|
||||
public function auth()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy auth, for SockLegacy. Remove when the old chat server finally dies.
|
||||
* @return string
|
||||
*/
|
||||
public function authLegacy()
|
||||
{
|
||||
$user = User::construct($_GET['arg1'] ?? null);
|
||||
$session = new Session($_GET['arg2'] ?? null);
|
||||
|
||||
if ($session->validate($user->id)
|
||||
&& !$user->permission(Site::DEACTIVATED)
|
||||
&& !$user->permission(Site::RESTRICTED)) {
|
||||
$hierarchy = $user->hierarchy();
|
||||
$moderator = $user->permission(Manage::USE_MANAGE, Perms::MANAGE) ? 1 : 0;
|
||||
$changeName = $user->permission(Site::CHANGE_USERNAME) ? 1 : 0;
|
||||
$createChans = $user->permission(Site::MULTIPLE_GROUPS) ? 2 : (
|
||||
$user->permission(Site::CREATE_GROUP) ? 1 : 0
|
||||
);
|
||||
|
||||
// The single 0 in here is used to determine log access, which isn't supported by sakurako anymore since it
|
||||
// required direct database access and the chat is databaseless now.
|
||||
return "yes{$user->id}\n{$user->username}\n{$user->colour}\n{$hierarchy}\f{$moderator}\f0\f{$changeName}\f{$createChans}\f";
|
||||
}
|
||||
|
||||
return "no";
|
||||
}
|
||||
}
|
||||
|
|
31
app/Middleware/EnableCORS.php
Normal file
31
app/Middleware/EnableCORS.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* Enables CORS globally.
|
||||
* @package Sakura
|
||||
*/
|
||||
|
||||
namespace Sakura\Middleware;
|
||||
|
||||
/**
|
||||
* Enables CORS.
|
||||
* @package Sakura
|
||||
* @author Julian van de Groep <me@flash.moe>
|
||||
*/
|
||||
class EnableCORS implements MiddlewareInterface
|
||||
{
|
||||
/**
|
||||
* Enables CORS.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if (isset($_SERVER['HTTP_ORIGIN'])) {
|
||||
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
|
||||
header('Access-Control-Allow-Credentials: true');
|
||||
header('Access-Control-Max-Age: 86400');
|
||||
header("Access-Control-Allow-Methods: GET, POST");
|
||||
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
|
||||
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
app/User.php
12
app/User.php
|
@ -1079,4 +1079,16 @@ class User
|
|||
{
|
||||
return Template::exists($this->design) ? $this->design : config('general.design');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user's proper (highest) hierarchy.
|
||||
* @return int
|
||||
*/
|
||||
public function hierarchy()
|
||||
{
|
||||
return DB::table('ranks')
|
||||
->join('user_ranks', 'ranks.rank_id', '=', 'user_ranks.rank_id')
|
||||
->where('user_id', $this->id)
|
||||
->max('ranks.rank_hierarchy');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ report_host =
|
|||
; Mailing settings
|
||||
[mail]
|
||||
contact_address = sakura@localhost
|
||||
signature = Sakura | http://localhost/
|
||||
signature = "Sakura | http://localhost/"
|
||||
|
||||
; SMTP settings
|
||||
[mail.smtp]
|
||||
|
@ -208,3 +208,39 @@ mail['Administrator'] = sakura@localghost
|
|||
twit['smugwave'] = "Sakura's main developer"
|
||||
|
||||
repo['Sakura'] = https://github.com/flashwave/sakura
|
||||
|
||||
; Chat specific settings
|
||||
[chat]
|
||||
; Path to the webclient
|
||||
webclient = http://localhost/chat/
|
||||
|
||||
; Protocol to use
|
||||
protocol = Sock
|
||||
|
||||
; Server address
|
||||
server = ws://localhost
|
||||
|
||||
; Window/tab title
|
||||
title = Sakurako
|
||||
|
||||
; Path to language files directory for the chat (relative to the chat's client)
|
||||
language_path = ./languages/
|
||||
|
||||
; Available languages
|
||||
languages[en-gb] = English
|
||||
languages[nl-nl] = Nederlands
|
||||
|
||||
; Default language
|
||||
language = en-gb
|
||||
|
||||
; Date formatting used for chat message (standard PHP format)
|
||||
date_format = H:i:s
|
||||
|
||||
; Markup parser to use
|
||||
parser = WaterDown
|
||||
|
||||
; Soundpacks
|
||||
sound_packs[default] = Default
|
||||
|
||||
; Default soundpack to use
|
||||
sound_pack = default
|
||||
|
|
|
@ -17,6 +17,13 @@ namespace Sakura
|
|||
Notifications.Start();
|
||||
}
|
||||
|
||||
public static Delete(id: number): void
|
||||
{
|
||||
var deleter: AJAX = new AJAX;
|
||||
deleter.SetUrl("/notifications/" + id + "/mark");
|
||||
deleter.Start(HTTPMethod.GET);
|
||||
}
|
||||
|
||||
public static Poll(): void
|
||||
{
|
||||
this.Client.Start(HTTPMethod.GET);
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace Yuuno
|
|||
Sakura.DOM.Append(inner, text);
|
||||
Sakura.DOM.Append(container, inner);
|
||||
|
||||
close.setAttribute('onclick', 'Yuuno.Notifications.CloseAlert(this.parentNode.id);');
|
||||
close.setAttribute('onclick', (alert.id ? 'Sakura.Notifications.Delete(' + alert.id + ');' : '') + 'Yuuno.Notifications.CloseAlert(this.parentNode.id)');
|
||||
|
||||
Sakura.DOM.Append(close, closeIcon);
|
||||
Sakura.DOM.Append(container, close);
|
||||
|
@ -58,7 +58,12 @@ namespace Yuuno
|
|||
|
||||
if (alert.timeout > 0) {
|
||||
setTimeout(() => {
|
||||
Notifications.CloseAlert(id);
|
||||
if (Sakura.DOM.ID(id)) {
|
||||
if (alert.id) {
|
||||
Sakura.Notifications.Delete(alert.id);
|
||||
}
|
||||
Notifications.CloseAlert(id);
|
||||
}
|
||||
}, alert.timeout);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,9 +79,6 @@ Router::group(['before' => 'maintenance'], function () {
|
|||
'mcptest' => 'manage.index',
|
||||
//'report' => 'report.something',
|
||||
//'osu' => 'eventual link to flashii team',
|
||||
//'filehost' => '???',
|
||||
//'fhscript' => '???',
|
||||
//'fhmanager' => '???',
|
||||
'everlastingness' => 'https://i.flash.moe/18661469927746.txt',
|
||||
'fuckingdone' => 'https://i.flash.moe/18671469927761.txt',
|
||||
];
|
||||
|
@ -119,8 +116,13 @@ Router::group(['before' => 'maintenance'], function () {
|
|||
Router::group(['prefix' => 'chat'], function () {
|
||||
Router::get('/redirect', 'ChatController@redirect', 'chat.redirect');
|
||||
Router::get('/settings', 'ChatController@settings', 'chat.settings');
|
||||
Router::get('/auth', 'ChatController@auth', 'chat.auth');
|
||||
Router::get('/resolve', 'Chatcontroller@resolve', 'chat.resolve');
|
||||
});
|
||||
|
||||
// Authentication for the "old" chat
|
||||
Router::get('/web/sock-auth.php', 'ChatController@authLegacy');
|
||||
|
||||
// Forum
|
||||
Router::group(['prefix' => 'forum'], function () {
|
||||
// Post
|
||||
|
|
10
utility.php
10
utility.php
|
@ -23,9 +23,15 @@ function config($value)
|
|||
}
|
||||
|
||||
// Alias for Router::route
|
||||
function route($name, $args = null)
|
||||
function route($name, $args = null, $full = false)
|
||||
{
|
||||
return Router::route($name, $args);
|
||||
return ($full ? full_domain() : '') . Router::route($name, $args);
|
||||
}
|
||||
|
||||
// Getting the full domain (+protocol) of the current host, only works for http
|
||||
function full_domain()
|
||||
{
|
||||
return 'http' . ($_SERVER['HTTPS'] ?? false ? 's' : '') . '://' . $_SERVER['HTTP_HOST'];
|
||||
}
|
||||
|
||||
// Checking if a parameter is equal to session_id()
|
||||
|
|
Reference in a new issue