что-то очень интересное!

This commit is contained in:
themohooks 2025-02-07 17:33:19 +03:00
parent 3455e55f71
commit 0226560702
34 changed files with 1602 additions and 347 deletions

View file

@ -4,15 +4,15 @@ namespace App\Controllers\Api\Images\Comments;
use App\Services\{Auth, Router, GenerateRandomStr, DB, Json, Files, Shell}; use App\Services\{Auth, Router, GenerateRandomStr, DB, Json, Files, Shell};
use App\Models\Notification; use App\Models\Notification;
use App\Services\Upload as Upload;
class Create class Create
{ {
static $filesrc;
private static function create($content, $id) private static function create($content, $id)
{ {
DB::query('INSERT INTO photos_comments VALUES (\'0\', :userid, :postid, :postbody, :time, :content)', array('postid' => $_POST['id'], ':postbody' => $_POST['wtext'], ':userid' => Auth::userid(), ':time' => time(), ':content'=>'')); DB::query('INSERT INTO photos_comments VALUES (\'0\', :userid, :postid, :postbody, :time, :content)', array('postid' => $_POST['id'], ':postbody' => $_POST['wtext'], ':userid' => Auth::userid(), ':time' => time(), ':content'=>$content));
} }
public function __construct() public function __construct()
{ {
@ -21,15 +21,54 @@ class Create
if ((int)$id === DB::query('SELECT id FROM photos WHERE id=:id', array(':id' => $id))[0]['id']) { if ((int)$id === DB::query('SELECT id FROM photos WHERE id=:id', array(':id' => $id))[0]['id']) {
$content = Json::return( if ($_FILES['filebody']['error'] != 4) {
array( $finfo = finfo_open(FILEINFO_MIME_TYPE);
'type' => 'none', $mime = finfo_file($finfo, $_FILES['filebody']['tmp_name']);
'by' => 'user' finfo_close($finfo);
) $filename = GenerateRandomStr::gen_uuid();
); if (preg_match('/^image\//', $mime)) {
$info = getimagesize($_FILES['filebody']['tmp_name']);
if (strlen($postbody) < 4096 || strlen($postbody) > 1) { if ($info['mime'] == 'image/jpeg')
if (trim($postbody) != '') { $image = imagecreatefromjpeg($_FILES['filebody']['tmp_name']);
elseif ($info['mime'] == 'image/gif')
$image = imagecreatefromgif($_FILES['filebody']['tmp_name']);
elseif ($info['mime'] == 'image/png')
$image = imagecreatefrompng($_FILES['filebody']['tmp_name']);
$type = 'img';
$destination = '/cdn/temp/'.$filename.'.jpg';
imagejpeg($image, $_SERVER['DOCUMENT_ROOT'].$destination, 60);
} else if (preg_match('/^audio\//', $mime)) {
return "Аудио";
} else if (preg_match('/^video\//', $mime)) {
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$ffmpeg = \FFMpeg\FFMpeg::create(array(
'ffmpeg.binaries' => $_SERVER['DOCUMENT_ROOT'] . '/app/Controllers/Exec/ffmpeg.exe',
'ffprobe.binaries' => $_SERVER['DOCUMENT_ROOT'] . '/app/Controllers/Exec/ffprobe.exe',
'timeout' => 3600, // The timeout for the underlying process
'ffmpeg.threads' => 12, // The number of threads that FFMpeg should use
), $logger);
} else {
$ffmpeg = \FFMpeg\FFMpeg::create();
}
$video = $ffmpeg->open($_FILES['filebody']['tmp_name']);
$video->save(new \FFMpeg\Format\Video\X264(), $_SERVER['DOCUMENT_ROOT'] . "/cdn/temp/" . $filename . '.mp4');
$video->frame(\FFMpeg\Coordinate\TimeCode::fromSeconds(1))->save($_SERVER['DOCUMENT_ROOT'] . "/cdn/temp/VIDPRV_" . $filename . '.jpg');
$type = 'video';
$destination = '/cdn/temp/'.$filename.'.mp4';
$destination_vidprv = '/cdn/temp/VIDPRV'.$filename.'.jpg';
} else {
return "Неизвестный тип файла";
}
$upload = new Upload($_SERVER['DOCUMENT_ROOT'].$destination, 'cdn/'.$type.'/');
self::$filesrc = $upload->getSrc();
}
if ((strlen($postbody) < 4096 || strlen($postbody) > 1) || $_FILES['filebody']['error'] != 4) {
if (trim($postbody) != '' || $_FILES['filebody']['error'] != 4) {
$postbody = ltrim($postbody); $postbody = ltrim($postbody);
echo json_encode( echo json_encode(
array( array(
@ -48,17 +87,24 @@ class Create
} else { } else {
die(json_encode( die(json_encode(
array( array(
'errorcode' => '1', 'errorcode' => '2',
'error' => 1 'error' => 1
) )
)); ));
} }
$content = Json::return(
array(
'type' => 'none',
'by' => 'user',
'filetype' => $type,
'src' => self::$filesrc
)
);
self::create($content, $id); self::create($content, $id);
} else { } else {
die(json_encode( die(json_encode(
array( array(
'errorcode' => '1', 'errorcode' => '3',
'error' => 1 'error' => 1
) )
)); ));

View file

@ -15,7 +15,7 @@ class Rate
if (isset($_GET['vote']) && isset($_GET['pid'])) { if (isset($_GET['vote']) && isset($_GET['pid'])) {
if (Vote::photo(Auth::userid(), $_GET['pid']) === -1) { if (Vote::photo(Auth::userid(), $_GET['pid']) === -1) {
DB::query('INSERT INTO photos_rates VALUES (\'0\', :id, :pid, :type)', array(':id'=>Auth::userid(), ':pid' => $_GET['pid'], ':type'=>$_GET['vote'])); DB::query('INSERT INTO photos_rates VALUES (\'0\', :id, :pid, :type, 0)', array(':id'=>Auth::userid(), ':pid' => $_GET['pid'], ':type'=>$_GET['vote']));
if (Vote::photo(Auth::userid(), $_GET['pid']) != $_GET['vote']) { if (Vote::photo(Auth::userid(), $_GET['pid']) != $_GET['vote']) {
DB::query('DELETE FROM photos_rates WHERE user_id=:id AND photo_id=:pid AND type=:type', array(':id'=>Auth::userid(), ':pid' => $_GET['pid'], ':type'=>Vote::photo(Auth::userid(), $_GET['pid']))); DB::query('DELETE FROM photos_rates WHERE user_id=:id AND photo_id=:pid AND type=:type', array(':id'=>Auth::userid(), ':pid' => $_GET['pid'], ':type'=>Vote::photo(Auth::userid(), $_GET['pid'])));
} }

View file

@ -7,7 +7,9 @@ use \App\Controllers\ExceptionRegister;
use \App\Core\Page; use \App\Core\Page;
use donatj\UserAgent\UserAgentParser; use donatj\UserAgent\UserAgentParser;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use Beeyev\DisposableEmailFilter\DisposableEmailFilter;
class Register class Register
{ {
@ -294,6 +296,7 @@ class Register
$password = $_POST['password']; $password = $_POST['password'];
$email = $_POST['email']; $email = $_POST['email'];
$forbusernames = explode(',', NGALLERY['root']['registration']['prohibited_usernames']); $forbusernames = explode(',', NGALLERY['root']['registration']['prohibited_usernames']);
$status = 0;
if (!self::checkforb($_POST['username'], $forbusernames)) { if (!self::checkforb($_POST['username'], $forbusernames)) {
if (!strcasecmp(DB::query('SELECT username FROM users WHERE (LOWER(username) LIKE :username)', array(':username' => '%' . $username . '%'))[0]['username'], $username) === false) { if (!strcasecmp(DB::query('SELECT username FROM users WHERE (LOWER(username) LIKE :username)', array(':username' => '%' . $username . '%'))[0]['username'], $username) === false) {
@ -315,11 +318,107 @@ class Register
'regdate' => time() 'regdate' => time()
) )
); );
if (NGALLERY['root']['registration']['emailverify'] == 'true') {
$status === 3;
}
DB::query('INSERT INTO users VALUES (\'0\', :username, :email, :password, :photourl, 5, :online, 0, :status, :content)', array(':username' => ltrim($username), ':password' => password_hash(ltrim($password), PASSWORD_BCRYPT), ':photourl' => '/static/img/avatar.png', ':email' => $email, ':content' => $content, ':online' => time(), ':status'=>$status));
if (NGALLERY['root']['registration']['emailverify'] == 'true') {
$disposableEmailFilter = new DisposableEmailFilter();
if ($disposableEmailFilter->isDisposableEmailAddress($_POST['email'])) {
echo json_encode(
array(
'errorcode' => '9',
'errortitle' => 'Почта запрещена для регистрации',
'error' => 1
)
);
die();
}
$token = GenerateRandomStr::gen_uuid();
$user_id = DB::query('SELECT id FROM users WHERE username=:username', array(':username' => $username))[0]['id'];
$key = GenerateRandomStr::gen_uuid();
$content = Json::return(
array(
'user_id' => $user_id
)
);
$mail = new PHPMailer(true);
DB::query('INSERT INTO servicekeys VALUES (\'0\', :token, :type, 1, :content)', array(':token'=>$key, ':type'=>'EMAILVERIFY', ':content'=>$content));
try {
$mail->isSMTP();
$mail->Host = NGALLERY['root']['email']['credentials']['host'];
$mail->SMTPAuth = true;
$mail->CharSet = "UTF-8";
$mail->Username = NGALLERY['root']['email']['credentials']['username'];
$mail->Password = NGALLERY['root']['email']['credentials']['password'];
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
$mail->Port = NGALLERY['root']['email']['credentials']['port'];
$mail->setFrom(NGALLERY['root']['email']['from']['address'], NGALLERY['root']['title']);
$mail->addAddress($_POST['email']);
$mail->isHTML(true);
$mail->Subject = 'Подтверждение регистрации | '.NGALLERY['root']['title'];
$mail->Body = '
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 20px;
}
.container {
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding: 20px;
max-width: 600px;
margin: auto;
}
h1 {
color: #333;
}
.code {
font-size: 24px;
font-weight: bold;
color: #007bff;
margin: 20px 0;
}
.footer {
margin-top: 20px;
font-size: 12px;
color: #777;
}
</style>
</head>
<body>
<div class="container">
<h1>Подтверждение регистрации</h1>
<p>Это письмо было отправлено на ваш почтовый ящик, так как оно было указано при регистрации на '.NGALLERY['root']['title'].' ('.$_SERVER['HTTP_HOST'].')<br>Если вы его не запрашивали, проигнорируйте его.</p><br><br>Ссылка для подтверждения адреса: <a href="https://'.$_SERVER['HTTP_HOST'].'/api/users/emailverify?token='.$key.'">https://'.$_SERVER['HTTP_HOST'].'/api/users/emailverify?token='.$key.'</a>
</div>
</body>
</html>';
$mail->send();
} catch (Exception $e) {
echo json_encode(
array(
'errorcode' => '8',
'errortitle' => 'Не удалось отправить письмо: '.$mail->ErrorInfo,
'error' => 1,
)
);
die();
}
}
DB::query('INSERT INTO users VALUES (\'0\', :username, :email, :password, :photourl, 5, :online, 0, 0, :content)', array(':username' => ltrim($username), ':password' => password_hash(ltrim($password), PASSWORD_BCRYPT), ':photourl' => '/static/img/avatar.png', ':email' => $email, ':content' => $content, ':online' => time()));
$cstrong = True;
$token = GenerateRandomStr::gen_uuid();
$user_id = DB::query('SELECT id FROM users WHERE username=:username', array(':username' => $username))[0]['id'];
if (!empty($_SERVER['HTTP_CLIENT_IP'])) { if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP']; $ip = $_SERVER['HTTP_CLIENT_IP'];
@ -328,19 +427,11 @@ class Register
} else { } else {
$ip = $_SERVER['REMOTE_ADDR']; $ip = $_SERVER['REMOTE_ADDR'];
} }
$parser = new UserAgentParser();
$ua = $parser->parse();
$ua = $parser();
$servicekey = GenerateRandomStr::gen_uuid();
$url = 'http://ip-api.com/json/' . $ip; $url = 'http://ip-api.com/json/' . $ip;
$response = file_get_contents($url); $response = file_get_contents($url);
$data = json_decode($response, true); $data = json_decode($response, true);
$loc = $data['country'] . ', ' . $data['city'];
DB::query('INSERT INTO login_tokens VALUES (\'0\', :token, :user_id)', array( DB::query('INSERT INTO login_tokens VALUES (\'0\', :token, :user_id)', array(
':token' => $token, ':token' => $token,
':user_id' => $user_id, ':user_id' => $user_id,
@ -350,7 +441,6 @@ class Register
setcookie("NGALLERYSESS", $token, time() + 120 * 180 * 240 * 720, '/', NULL, NULL, TRUE); setcookie("NGALLERYSESS", $token, time() + 120 * 180 * 240 * 720, '/', NULL, NULL, TRUE);
setcookie("NGALLERYSESS_", '1', time() + 120 * 180 * 240 * 360, '/', NULL, NULL, TRUE); setcookie("NGALLERYSESS_", '1', time() + 120 * 180 * 240 * 360, '/', NULL, NULL, TRUE);
setcookie("NGALLERYID", $user_id, time() + 10 * 10 * 24 * 72, '/', NULL, NULL, TRUE); setcookie("NGALLERYID", $user_id, time() + 10 * 10 * 24 * 72, '/', NULL, NULL, TRUE);
echo json_encode( echo json_encode(
array( array(
'errorcode' => '0', 'errorcode' => '0',

View file

@ -0,0 +1,25 @@
<?php
namespace App\Controllers\Api\Users;
use App\Services\{Auth, Router, GenerateRandomStr, DB, Json, EXIF};
use App\Models\{User, Vote};
use \App\Core\Page;
class EmailVerify
{
public function __construct()
{
if (isset($_GET['token'])) {
$data = DB::query('SELECT * FROM servicekeys WHERE token=:token AND type="EMAILVERIFY"', array(':token'=>$_GET['token']))[0];
$user_id = json_decode($data['content'], true)['user_id'];
if ($data['status'] != 0) {
DB::query('UPDATE users SET status=0 WHERE id=:id', [':id' => $user_id]);
DB::query('UPDATE servicekeys SET status=0 WHERE token=:id', [':id' => $_GET['token']]);
Page::set('System/EmailVerify');
}
}
}
}

View file

@ -21,6 +21,7 @@ use \App\Controllers\Api\Images\Comments\Rate as PhotoCommentVote;
use \App\Controllers\Api\Vehicles\Load as VehiclesLoad; use \App\Controllers\Api\Vehicles\Load as VehiclesLoad;
use \App\Controllers\Api\Profile\Update as ProfileUpdate; use \App\Controllers\Api\Profile\Update as ProfileUpdate;
use \App\Controllers\Api\Users\LoadUser as UserLoad; use \App\Controllers\Api\Users\LoadUser as UserLoad;
use \App\Controllers\Api\Users\EmailVerify as EmailVerify;
use \App\Controllers\Api\Admin\Images\SetVisibility as AdminPhotoSetVisibility; use \App\Controllers\Api\Admin\Images\SetVisibility as AdminPhotoSetVisibility;
use \App\Controllers\Api\Admin\CreateNews as AdminCreateNews; use \App\Controllers\Api\Admin\CreateNews as AdminCreateNews;
use \App\Controllers\Api\Admin\LoadNews as AdminLoadNews; use \App\Controllers\Api\Admin\LoadNews as AdminLoadNews;
@ -38,6 +39,9 @@ class ApiController
public static function upload() { public static function upload() {
return new Upload(); return new Upload();
} }
public static function emailverify() {
return new EmailVerify();
}
public static function photovote() { public static function photovote() {
return new PhotoVote(); return new PhotoVote();
} }

View file

@ -0,0 +1,27 @@
$tempfile = $args[0]
$weburl = $args[1]
$id = $args[2]
#$tempfile = 'G:\video.mp4'
#$weburl = 'kandle.loc'
#$id = '40'
$hash = -join (((48..57)+(65..90)+(97..122)) * 80 |Get-Random -Count 32 |%{[char]$_})
$hashT = -join (((48..57)+(65..90)+(97..122)) * 80 |Get-Random -Count 222 |%{[char]$_})
$temp = [System.IO.Path]::GetTempFileName()
$shell = Get-WmiObject Win32_process -filter "ProcessId = $PID"
$shell.SetPriority(16384)
Copy-Item $tempfile E:\$hash
E:\Maksim\kandle\app\Controllers\Video\Exec\ffmpeg.exe -i E:\$hash -c:v libx264 -q:v 7 -c:a libmp3lame -q:a 4 -tune zerolatency -y C:\kandletemp\$hashT.mp4
$uri = 'http://'+$weburl+'/api/video/exec/upload?file=C:\kandletemp\'+$hashT+'.mp4&videoid='+$id
Invoke-WebRequest -Uri $uri
Remove-Item C:\kandletemp\$hashT.mp4

View file

@ -0,0 +1,14 @@
tmpfile="$RANDOM-$(date +%s%N)"
copyfile="$0"
weburl="$1"
videoid="$2"
#copyfile='/var/www/fastuser/data/www/kandle.cats.ovh/video.mp4'
#weburl='kandle.loc'
#videoid='1'
cp $1 "/tmp/vid_$tmpfile.bin"
nice -n 20 ffmpeg -i "/tmp/vid_$tmpfile.bin" -c:v libx264 -q:v 7 -c:a libmp3lame -q:a 4 -tune zerolatency -y "$4/cdn/temp/ffmOi$tmpfile.mp4"
curl "http://$2/api/video/exec/upload?file=$4/cdn/temp/ffmOi$tmpfile.mp4&videoid=$3"

Binary file not shown.

Binary file not shown.

View file

@ -72,6 +72,16 @@ class MainController
{ {
Page::set('FavAuthors'); Page::set('FavAuthors');
}
public static function emailverify()
{
Page::set('Errors/EmailVerify');
}
public static function tour()
{
Page::set('Tour');
} }
public static function robots() { public static function robots() {
echo 'User-Agent: * echo 'User-Agent: *

View file

@ -27,12 +27,14 @@ class Routes
Router::get('/rules/photo', 'MainController@photoRules'); Router::get('/rules/photo', 'MainController@photoRules');
Router::get('/rules/video', 'MainController@videoRules'); Router::get('/rules/video', 'MainController@videoRules');
Router::get('/feed', 'MainController@feed'); Router::get('/feed', 'MainController@feed');
Router::get('/tour', 'MainController@tour');
Router::get('/update', 'MainController@update'); Router::get('/update', 'MainController@update');
Router::get('/top30', 'MainController@top30'); Router::get('/top30', 'MainController@top30');
Router::get('/photoext', 'PhotoController@photoext'); Router::get('/photoext', 'PhotoController@photoext');
Router::get('/api/photo/compress', 'ApiController@photocompress'); Router::get('/api/photo/compress', 'ApiController@photocompress');
Router::get('/api/photo/loadrecent', 'ApiController@recentphotos'); Router::get('/api/photo/loadrecent', 'ApiController@recentphotos');
Router::get('/api/users/load/$id', 'ApiController@loaduser'); Router::get('/api/users/load/$id', 'ApiController@loaduser');
Router::get('/api/users/emailverify', 'ApiController@emailverify');
Router::get('/article/$id', 'MainController@gallery'); Router::get('/article/$id', 'MainController@gallery');
@ -43,7 +45,6 @@ class Routes
Router::get('/lk/history', 'ProfileController@lkhistory'); Router::get('/lk/history', 'ProfileController@lkhistory');
Router::get('/lk/profile', 'ProfileController@lkprofile'); Router::get('/lk/profile', 'ProfileController@lkprofile');
Router::get('/lk/pday', 'ProfileController@photoindexhistory'); Router::get('/lk/pday', 'ProfileController@photoindexhistory');
Router::get('/fav_authors', 'MainController@favauthors'); Router::get('/fav_authors', 'MainController@favauthors');
Router::get('/search', 'SearchController@i'); Router::get('/search', 'SearchController@i');

View file

@ -1,68 +1,83 @@
<?php <?php
namespace App\Models; namespace App\Models;
use \App\Services\{DB, Date, Auth}; use \App\Services\{DB, Date, Auth};
use \App\Models\{User, Photo, Vote}; use \App\Models\{User, Photo, Vote};
class Comment { class Comment
{
public $commentid; public $commentid;
public $c; public $c;
public $class; public $class;
function __construct($user_id) { function __construct($user_id)
{
$this->c = $user_id; $this->c = $user_id;
} }
public function class($class) { public function class($class)
{
$this->class = $class; $this->class = $class;
} }
public function content($table) { public function content($table)
{
$content = json_decode($this->c['content'], true); $content = json_decode($this->c['content'], true);
return $content[$table]; return $content[$table];
} }
public function i() { public function i()
{
$user = new User($this->c['user_id']); $user = new User($this->c['user_id']);
$content = json_decode($this->c['content'], true); $content = json_decode($this->c['content'], true);
echo '<div class="'.$this->class.' comment" wid="'.$this->c['id'].'"> echo '<div class="' . $this->class . ' comment" wid="' . $this->c['id'] . '">
<div style="float:right; text-align:right" class="sm"> <div style="float:right; text-align:right" class="sm">
<span class="message_date">'.Date::zmdate($this->c['posted_at']).'</span><br> <span class="message_date">' . Date::zmdate($this->c['posted_at']) . '</span><br>
<a href="#" class="quoteLink dot">Цитировать</a> <a href="#" class="quoteLink dot">Цитировать</a>
· ·
<a href="#'.$this->c['id'].'" class="cmLink dot">Ссылка</a> <a href="#' . $this->c['id'] . '" class="cmLink dot">Ссылка</a>
'; ';
echo ' echo '
</div> </div>
<a name="2681468"></a><a name="last"></a> <a name="2681468"></a><a name="last"></a>
<div><img src="'.$user->i('photourl').'" width="32" style="border-radius: 3px; margin-right: 5px;"><b><a href="/author/'.$this->c['user_id'].'/" class="message_author">'.htmlspecialchars($user->i('username')).'</a></b> &middot; <div><img src="' . $user->i('photourl') . '" width="32" style="border-radius: 3px; margin-right: 5px;"><b><a href="/author/' . $this->c['user_id'] . '/" class="message_author">' . htmlspecialchars($user->i('username')) . '</a></b> &middot;
<span class="flag">'; <span class="flag">';
if (json_decode($user->i('content'), true)['aboutrid']['value'] != null) { if (json_decode($user->i('content'), true)['aboutrid']['value'] != null) {
echo '<img src="/static/img/flags/'.json_decode($user->i('content'), true)['aboutrid']['value'].'.gif">'; echo '<img src="/static/img/flags/' . json_decode($user->i('content'), true)['aboutrid']['value'] . '.gif">';
} }
if (json_decode($user->i('content'), true)['aboutlive']['value'] != null) { if (json_decode($user->i('content'), true)['aboutlive']['value'] != null) {
echo ' '.htmlspecialchars(json_decode($user->i('content'), true)['aboutlive']['value']); echo ' ' . htmlspecialchars(json_decode($user->i('content'), true)['aboutlive']['value']);
} }
if ($content['edited'] === 'true') { if ($content['edited'] === 'true') {
echo '<br>(отредактировано)'; echo '<br>(отредактировано)';
} }
if ($user->i('admin') === 1) { if ($user->i('admin') === 1) {
$admintype = ' · Администратор сервера'; $admintype = ' · Администратор сервера';
} else if ($user->i('admin') === 2) { } else if ($user->i('admin') === 2) {
$admintype = ' · Фотомодератор'; $admintype = ' · Фотомодератор';
} }
if ((int)Vote::countcommrates($this->c['id'], -1) >= 1) { if ((int)Vote::countcommrates($this->c['id'], -1) >= 1) {
$commclass = 'pro'; $commclass = 'pro';
$symb = '+'; $symb = '+';
} else if ((int)Vote::countcommrates($this->c['id'], -1) < 0) { } else if ((int)Vote::countcommrates($this->c['id'], -1) < 0) {
$commclass = 'con'; $commclass = 'con';
$symb = ''; $symb = '';
} else if ((int)Vote::countcommrates($this->c['id'], -1) === 0) { } else if ((int)Vote::countcommrates($this->c['id'], -1) === 0) {
$commclass = ''; $commclass = '';
} }
echo '</span></div> echo '</span></div>
<div class="rank">Фото: '.Photo::fetchAll($this->c['user_id']).' '.$admintype.'</div> <div class="rank">Фото: ' . Photo::fetchAll($this->c['user_id']) . ' ' . $admintype . '</div>
<div class="message-text">'.preg_replace("~(?:[\p{M}]{1})([\p{M}])+?~uis","", htmlspecialchars($this->c['body'])).'</div> <div class="message-text">' . preg_replace("~(?:[\p{M}]{1})([\p{M}])+?~uis", "", htmlspecialchars($this->c['body'])) . '</div>
';
if ($content['filetype'] === 'img') {
echo '<div class="message-text"><img src="'.$content['src'].'" width="250"></div>';
}
if ($content['filetype'] === 'video') {
echo '<div class="message-text"><video controls src="'.$content['src'].'" width="250"></div>';
}
echo '
<div class="comment-votes-block"> <div class="comment-votes-block">
'; ';
echo '<style> echo '<style>
.dropdown { .dropdown {
position: relative; position: relative;
display: inline-block; display: inline-block;
@ -82,34 +97,31 @@ class Comment {
display: block; display: block;
} }
</style>'; </style>';
if ($this->c['user_id'] === Auth::userid()) { if ($this->c['user_id'] === Auth::userid()) {
echo ' echo '
<div class="dropdown"> <div class="dropdown">
<a style="color: #000" class="compl" href="/lk/ticket.php?action=add&amp;wid=3252565">...</a> <a style="color: #000" class="compl" href="/lk/ticket.php?action=add&amp;wid=3252565">...</a>
<div class="dropdown-content">'; ?> <div class="dropdown-content">'; ?>
<a style="margin-bottom: 10px;" href="#" onclick="createModal(<?=$this->c['id']?>, 'EDIT_COMMENT', '<?=htmlspecialchars($this->c['body'])?>', 'modaledit<?=$this->c['id']?>'); return false;">Редактировать</a><br> <a style="margin-bottom: 10px;" href="#" onclick="createModal(<?= $this->c['id'] ?>, 'EDIT_COMMENT', '<?= htmlspecialchars($this->c['body']) ?>', 'modaledit<?= $this->c['id'] ?>'); return false;">Редактировать</a><br>
<a href="#" onclick="createModal(<?=$this->c['id']?>, 'DELETE_COMMENT', '', 'modaldel<?=$this->c['id']?>'); return false;">Удалить</a> <a href="#" onclick="createModal(<?= $this->c['id'] ?>, 'DELETE_COMMENT', '', 'modaldel<?= $this->c['id'] ?>'); return false;">Удалить</a>
<?php <?php
echo ' echo '
</div> </div>
</div> </div>
'; ';
} }
echo ' echo '
<div class="wvote" wid="'.$this->c['id'].'"> <div class="wvote" wid="' . $this->c['id'] . '">
<a href="#" vote="1" class="w-btn s2"><span>+</span></a> <a href="#" vote="1" class="w-btn s2"><span>+</span></a>
<div class="w-rating '.$commclass.' active">'.$symb.Vote::countcommrates($this->c['id'], -1).'</div> <div class="w-rating ' . $commclass . ' active">' . $symb . Vote::countcommrates($this->c['id'], -1) . '</div>
<div class="w-rating-ext"> <div class="w-rating-ext">
<div><span class="pro">+'.Vote::countcommrates($this->c['id'], 1).'</span> / <span class="con">'.Vote::countcommrates($this->c['id'], 0).'</span></div> <div><span class="pro">+' . Vote::countcommrates($this->c['id'], 1) . '</span> / <span class="con">' . Vote::countcommrates($this->c['id'], 0) . '</span></div>
</div> </div>
<a href="#" vote="0" class="w-btn s5"><span></span></a> <a href="#" vote="0" class="w-btn s5"><span></span></a>
</div> </div>
</div> </div>
</div>'; </div>';
} }
} }

View file

@ -28,7 +28,7 @@ class Upload
$tmpname = $file['tmp_name']; $tmpname = $file['tmp_name'];
$type = explode('/', $file['type'])[0]; $type = explode('/', $file['type'])[0];
$name = $file['name']; $name = $file['name'];
$fileext = pathinfo($file['name']); $fileext = pathinfo($file['name'], PATHINFO_EXTENSION);
} else { } else {
$tmpname = $file; $tmpname = $file;
$type = filetype($file); $type = filetype($file);
@ -88,8 +88,6 @@ class Upload
$destination = "{$uploadDir}/" . basename($tmpname); $destination = "{$uploadDir}/" . basename($tmpname);
$this->type = $type; $this->type = $type;
$this->src = "/uploads/{$folder}"; $this->src = "/uploads/{$folder}";
$this->size = self::human_filesize(filesize($tmpname)); $this->size = self::human_filesize(filesize($tmpname));

View file

@ -20,6 +20,8 @@
"donatj/phpuseragentparser": "^1.8", "donatj/phpuseragentparser": "^1.8",
"php-ffmpeg/php-ffmpeg": "^1.2", "php-ffmpeg/php-ffmpeg": "^1.2",
"chriskonnertz/bbcode": "^1.1", "chriskonnertz/bbcode": "^1.1",
"paquettg/php-html-parser": "^2.2" "paquettg/php-html-parser": "^2.2",
"phpmailer/phpmailer": "^6.9",
"beeyev/disposable-email-filter-php": "^1.3"
} }
} }

160
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "31de33165b326f2edef27c1fc9ae5b08", "content-hash": "ec83690d34b55f6ada188bcfc6a299db",
"packages": [ "packages": [
{ {
"name": "aws/aws-crt-php", "name": "aws/aws-crt-php",
@ -155,6 +155,77 @@
}, },
"time": "2024-07-03T18:12:51+00:00" "time": "2024-07-03T18:12:51+00:00"
}, },
{
"name": "beeyev/disposable-email-filter-php",
"version": "v1.3.83",
"source": {
"type": "git",
"url": "https://github.com/beeyev/disposable-email-filter-php.git",
"reference": "9ee8422c390d0ce0fff25ff5616a4b9654f73bb0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/beeyev/disposable-email-filter-php/zipball/9ee8422c390d0ce0fff25ff5616a4b9654f73bb0",
"reference": "9ee8422c390d0ce0fff25ff5616a4b9654f73bb0",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"ext-json": "*",
"friendsofphp/php-cs-fixer": "^3.4",
"kubawerlos/php-cs-fixer-custom-fixers": "^3.7",
"phpstan/phpstan": "^1.11",
"phpstan/phpstan-phpunit": "^1.3",
"phpstan/phpstan-strict-rules": "^1.5",
"phpunit/phpunit": "^8.5 || ^9",
"symplify/phpstan-rules": "^12.3"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"DisposableEmail": "Beeyev\\DisposableEmailFilter\\Adapters\\Laravel\\Facades\\DisposableEmail"
},
"providers": [
"Beeyev\\DisposableEmailFilter\\Adapters\\Laravel\\DisposableEmailFilterServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Beeyev\\DisposableEmailFilter\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Alexander Tebiev",
"email": "alexander.tebiev@gmail.com",
"homepage": "https://github.com/beeyev/"
}
],
"description": "Disposable (temporary/throwaway/fake) email detection library. Automatically updated every week.",
"homepage": "https://github.com/beeyev/disposable-email-filter-php",
"keywords": [
"disposable",
"email",
"fake",
"temporary",
"throwaway"
],
"support": {
"docs": "https://github.com/beeyev/disposable-email-filter-php/",
"issues": "https://github.com/beeyev/disposable-email-filter-php/issues",
"rss": "https://github.com/beeyev/disposable-email-filter-php/releases.atom",
"source": "https://github.com/beeyev/disposable-email-filter-php.git"
},
"time": "2025-02-05T14:49:14+00:00"
},
{ {
"name": "chriskonnertz/bbcode", "name": "chriskonnertz/bbcode",
"version": "v1.1.2", "version": "v1.1.2",
@ -913,6 +984,87 @@
}, },
"time": "2024-01-02T10:37:01+00:00" "time": "2024-01-02T10:37:01+00:00"
}, },
{
"name": "phpmailer/phpmailer",
"version": "v6.9.3",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2f5c94fe7493efc213f643c23b1b1c249d40f47e",
"reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-filter": "*",
"ext-hash": "*",
"php": ">=5.5.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
"doctrine/annotations": "^1.2.6 || ^1.13.3",
"php-parallel-lint/php-console-highlighter": "^1.0.0",
"php-parallel-lint/php-parallel-lint": "^1.3.2",
"phpcompatibility/php-compatibility": "^9.3.5",
"roave/security-advisories": "dev-latest",
"squizlabs/php_codesniffer": "^3.7.2",
"yoast/phpunit-polyfills": "^1.0.4"
},
"suggest": {
"decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication",
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
"league/oauth2-google": "Needed for Google XOAUTH2 authentication",
"psr/log": "For optional PSR-3 debug logging",
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
"thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication"
},
"type": "library",
"autoload": {
"psr-4": {
"PHPMailer\\PHPMailer\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-only"
],
"authors": [
{
"name": "Marcus Bointon",
"email": "phpmailer@synchromedia.co.uk"
},
{
"name": "Jim Jagielski",
"email": "jimjag@gmail.com"
},
{
"name": "Andy Prevost",
"email": "codeworxtech@users.sourceforge.net"
},
{
"name": "Brent R. Matzelle"
}
],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.3"
},
"funding": [
{
"url": "https://github.com/Synchro",
"type": "github"
}
],
"time": "2024-11-24T18:04:13+00:00"
},
{ {
"name": "psr/cache", "name": "psr/cache",
"version": "3.0.0", "version": "3.0.0",
@ -2099,10 +2251,10 @@
"packages-dev": [], "packages-dev": [],
"aliases": [], "aliases": [],
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": [], "stability-flags": {},
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": [], "platform": {},
"platform-dev": [], "platform-dev": {},
"plugin-api-version": "2.6.0" "plugin-api-version": "2.6.0"
} }

View file

@ -13,6 +13,14 @@ ngallery:
type: 'allow' type: 'allow'
countries: '' countries: ''
cloudflare-caching: false cloudflare-caching: false
email:
credentials:
host: 'example@mail.com'
username: ''
password: ''
port: 465
from:
address:
db: db:
name: '' name: ''
host: '' host: ''
@ -40,6 +48,7 @@ ngallery:
proxy: true proxy: true
percent: 50 percent: 50
registration: registration:
emailverify: false
prohibited_usernames: '' prohibited_usernames: ''
access: access:
public: true public: true
@ -59,5 +68,3 @@ ngallery:
allowgif: true allowgif: true
comments: comments:
premoderation: false premoderation: false

View file

@ -57,7 +57,7 @@ CREATE TABLE `login_tokens` (
`id` int NOT NULL, `id` int NOT NULL,
`token` text NOT NULL, `token` text NOT NULL,
`user_id` int NOT NULL `user_id` int NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- -------------------------------------------------------- -- --------------------------------------------------------
@ -90,7 +90,7 @@ CREATE TABLE `photos` (
`place` text NOT NULL, `place` text NOT NULL,
`endmoderation` int NOT NULL DEFAULT '0', `endmoderation` int NOT NULL DEFAULT '0',
`content` text NOT NULL `content` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- -------------------------------------------------------- -- --------------------------------------------------------
@ -104,7 +104,7 @@ CREATE TABLE `photos_comments` (
`photo_id` int NOT NULL, `photo_id` int NOT NULL,
`body` text NOT NULL, `body` text NOT NULL,
`posted_at` int NOT NULL `posted_at` int NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- -------------------------------------------------------- -- --------------------------------------------------------
@ -117,7 +117,7 @@ CREATE TABLE `photos_comments_rates` (
`user_id` int NOT NULL, `user_id` int NOT NULL,
`comment_id` int NOT NULL, `comment_id` int NOT NULL,
`type` int NOT NULL `type` int NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- -------------------------------------------------------- -- --------------------------------------------------------
@ -130,7 +130,7 @@ CREATE TABLE `photos_rates` (
`user_id` int NOT NULL, `user_id` int NOT NULL,
`photo_id` int NOT NULL, `photo_id` int NOT NULL,
`type` int NOT NULL `type` int NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- -------------------------------------------------------- -- --------------------------------------------------------
@ -162,7 +162,7 @@ CREATE TABLE `users` (
`admin` int NOT NULL DEFAULT '0', `admin` int NOT NULL DEFAULT '0',
`status` int NOT NULL DEFAULT '0', `status` int NOT NULL DEFAULT '0',
`content` text NOT NULL `content` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- --
-- Индексы сохранённых таблиц -- Индексы сохранённых таблиц

View file

@ -7,7 +7,7 @@ CREATE TABLE IF NOT EXISTS `entities` (
`sampledata` text NOT NULL, `sampledata` text NOT NULL,
`color` text NOT NULL, `color` text NOT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `entities_data` ( CREATE TABLE IF NOT EXISTS `entities_data` (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
@ -17,21 +17,21 @@ CREATE TABLE IF NOT EXISTS `entities_data` (
`comment` text NOT NULL, `comment` text NOT NULL,
`content` text NOT NULL, `content` text NOT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `galleries` ( CREATE TABLE IF NOT EXISTS `galleries` (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`title` text NOT NULL, `title` text NOT NULL,
`opened` int NOT NULL, `opened` int NOT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `photos_favorite` ( CREATE TABLE IF NOT EXISTS `photos_favorite` (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`photo_id` int NOT NULL, `photo_id` int NOT NULL,
`user_id` int NOT NULL, `user_id` int NOT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `uploadindex_history` ( CREATE TABLE IF NOT EXISTS `uploadindex_history` (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
@ -42,7 +42,7 @@ CREATE TABLE IF NOT EXISTS `uploadindex_history` (
`type` int NOT NULL, `type` int NOT NULL,
`photo_id` int NOT NULL, `photo_id` int NOT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Изменение существующих таблиц -- Изменение существующих таблиц
@ -61,7 +61,7 @@ MODIFY COLUMN `online` int NOT NULL DEFAULT '0',
MODIFY COLUMN `admin` int NOT NULL; MODIFY COLUMN `admin` int NOT NULL;
-- Обновление кодировки для таблиц, использующих utf8 -- Обновление кодировки для таблиц, использующих utf8
ALTER TABLE `followers` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; ALTER TABLE `followers` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `followers_notifications` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; ALTER TABLE `followers_notifications` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `news` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; ALTER TABLE `news` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `photos_views` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; ALTER TABLE `photos_views` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

BIN
static/img/tour1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
static/img/tour2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
static/img/tour3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 KiB

BIN
static/kolya.mp3 Normal file

Binary file not shown.

View file

@ -27,6 +27,7 @@
<script src="/static/js/selector2.js<?php if (NGALLERY['root']['cloudflare-caching'] === true) { echo '?'.time(); } ?>"></script> <script src="/static/js/selector2.js<?php if (NGALLERY['root']['cloudflare-caching'] === true) { echo '?'.time(); } ?>"></script>
<script src="/static/js/selector.js<?php if (NGALLERY['root']['cloudflare-caching'] === true) { echo '?'.time(); } ?>"></script> <script src="/static/js/selector.js<?php if (NGALLERY['root']['cloudflare-caching'] === true) { echo '?'.time(); } ?>"></script>
<script src="/static/js/tablesort.js<?php if (NGALLERY['root']['cloudflare-caching'] === true) { echo '?'.time(); } ?>"></script> <script src="/static/js/tablesort.js<?php if (NGALLERY['root']['cloudflare-caching'] === true) { echo '?'.time(); } ?>"></script>
<link href='https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css' rel='stylesheet'>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css"> <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<div class="progress-container fixed-top"> <div class="progress-container fixed-top">

View file

@ -28,6 +28,12 @@ if ($noncheckedimgs > 0) {
?> ?>
<tr> <tr>
<?php
if (NGALLERY['root']['registration']['emailverify'] === true && $user->i('status') === 3) { ?>
<div class="label-orange" style="padding:10px; margin:0 -20px; color:#fff">
<center><h4 style="color:#fff; margin-bottom:3px">Пожалуйста, подтвердите свою почту</h4>
<div>Так мы сможем убедиться, что Вы настоящий человек. После подтверждения, Вам будет доступен полностью функционал сайта.<br><br><b>Письмо с ссылкой для подтверждения почты была отправлена на Ваш ящик, указанный при регистрации.</b></div></center></div>
<?php } ?>
<td class="mm-bar"> <td class="mm-bar">
<?php <?php
if (explode('/', $_SERVER['REQUEST_URI'])[1] === 'photo') { ?> if (explode('/', $_SERVER['REQUEST_URI'])[1] === 'photo') { ?>
@ -100,8 +106,10 @@ if ($noncheckedimgs > 0) {
?> ?>
<li><a href="/admin" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-info-circle"></i></span><span class="mm-label">Admin</span><?=$nonr?></a></li> <li><a href="/admin" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-info-circle"></i></span><span class="mm-label">Admin</span><?=$nonr?></a></li>
<?php } ?> <?php }
if (NGALLERY['root']['registration']['emailverify'] != true || $user->i('status') != 3) { ?>
<li><a href="/lk/upload" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-plus-square"></i></span><span class="mm-label"><b>Предложить медиа</b></span></a></li> <li><a href="/lk/upload" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-plus-square"></i></span><span class="mm-label"><b>Предложить медиа</b></span></a></li>
<?php } ?>
<li><a href="/lk/history" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-images"></i></span><span class="mm-label">Журнал</span></a></li> <li><a href="/lk/history" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-images"></i></span><span class="mm-label">Журнал</span></a></li>
<li><a href="/lk/konkurs.php" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-compass"></i></span><span class="mm-label">Конкурс</span></a></li> <li><a href="/lk/konkurs.php" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-compass"></i></span><span class="mm-label">Конкурс</span></a></li>
<li><a href="/lk/vehicles.php" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-folder-plus"></i></span><span class="mm-label"><b>Правка БД</b></span></a></li> <li><a href="/lk/vehicles.php" class="mm-item"><span class="mm-icon"><i class="fas fa-sm fa-fw fa-folder-plus"></i></span><span class="mm-label"><b>Правка БД</b></span></a></li>

View file

@ -1,46 +0,0 @@
<?php
header("HTTP/1.1 403 Forbidden");
?>
<html>
<head>
<style>body {
font-family: sans-serif;
position: relative;
height: 100vh;
overflow: hidden;
}
#dbErrorBody {
position: absolute;
top: 50%;
left: 50%;
margin-right: -50%;
transform: translate(-50%, -50%);
width: 400px;
text-align: center;
}
#dbErrorBody h1 {
margin-top: 5px;
margin-bottom: 2px;
}
#dbErrorBody span {
color: grey;
}
#dbErrorBody img {
max-width: 256px;
}
</style>
<title>Resource Busy</title>
</head>
<body>
<div id="dbErrorBody">
<img src="/static/img/busy.png" alt="Error">
<h1>Вы не участвуете в программе тестирования Birux Streams</h1>
<span>К сожалению, мы уже набрали достаточное количество участников. Следующая волна заявок будет скоро следите в Telegram-канале
<a href="https://t.me/biruxch">Birux</a>
</span>
</div>
</body>
</html>

View file

@ -1,44 +0,0 @@
<?php
header("HTTP/1.1 403 Forbidden");
?>
<html>
<head>
<style>body {
font-family: sans-serif;
position: relative;
height: 100vh;
overflow: hidden;
}
#dbErrorBody {
position: absolute;
top: 50%;
left: 50%;
margin-right: -50%;
transform: translate(-50%, -50%);
width: 400px;
text-align: center;
}
#dbErrorBody h1 {
margin-top: 5px;
margin-bottom: 2px;
}
#dbErrorBody span {
color: grey;
}
#dbErrorBody img {
max-width: 256px;
}
</style>
<title>Resource Busy</title>
</head>
<body>
<div id="dbErrorBody">
<img src="/static/img/busy.png" alt="Error">
<h1>Доступ запрещён!</h1>
<span>Такие дела. Эфир не принадлежит вам.</span>
</div>
</body>
</html>

View file

@ -247,7 +247,7 @@ if ($photo->i('id') !== null) {
<div class="rtext">Рейтинг: <b id="rating"><?= Vote::count($id) ?></b></div> <div class="rtext">Рейтинг: <b id="rating"><?= Vote::count($id) ?></b></div>
<div class="star" pid="1361063"></div> <div class="star" pid="1361063"></div>
<?php <?php
if (Auth::userid() > 0) { ?> if (Auth::userid() > 0 && (NGALLERY['root']['registration']['emailverify'] != true || $user->i('status') != 3)) { ?>
<div class="vote" pid="<?= $id ?>"> <div class="vote" pid="<?= $id ?>">
<a href="#" vote="1" class="vote_btn <?php if (Vote::photo(Auth::userid(), $id) === 1) { <a href="#" vote="1" class="vote_btn <?php if (Vote::photo(Auth::userid(), $id) === 1) {
echo 'voted'; echo 'voted';
@ -255,8 +255,9 @@ if ($photo->i('id') !== null) {
<a href="#" vote="0" class="vote_btn <?php if (Vote::photo(Auth::userid(), $id) === 0) { <a href="#" vote="0" class="vote_btn <?php if (Vote::photo(Auth::userid(), $id) === 0) {
echo 'voted'; echo 'voted';
} ?>"><span>Мне не&nbsp;нравится</span></a> } ?>"><span>Мне не&nbsp;нравится</span></a>
<!--a class="konk_btn" vote="1" href="#"><span>Красиво, на&nbsp;конкурс!</span></!--a>
<a-- href="#" vote="0" class="konk_btn"><span>Неконкурсное фото</span></a--> <a class="konk_btn" vote="1" href="#"><span>Красиво, на&nbsp;конкурс!</span></a>
<a href="#" vote="0" class="konk_btn"><span>Неконкурсное фото</span></a>
</div> </div>
<?php } ?> <?php } ?>
<div id="votes" class="votes"> <div id="votes" class="votes">
@ -616,21 +617,100 @@ if ($photo->i('id') !== null) {
</div> </div>
<div class="cmt-write s1"> <div class="cmt-write s1">
<h4 class="pp-item-header">Ваш комментарий</h4> <h4 class="pp-item-header">Ваш комментарий</h4>
<div style="padding:0 11px 11px"> <div style="padding:0 11px 11px">
<form action="/comment.php" method="post" id="f1"> <?php
if (Auth::userid() > 0) {
if (NGALLERY['root']['registration']['emailverify'] != true || $user->i('status') != 3) { ?>
<form action="/comment.php" method="post" id="f1" enctype="multipart/form-data">
<input type="hidden" name="sid" value="hgdl6old9r9qodmvkn1r4t7d6h"> <input type="hidden" name="sid" value="hgdl6old9r9qodmvkn1r4t7d6h">
<input type="hidden" name="last_comment_rand" value="893329610"> <input type="hidden" name="last_comment_rand" value="893329610">
<input type="hidden" name="id" id="id" value="<?= $id ?>"> <input type="hidden" name="id" id="id" value="<?= $id ?>">
<input type="hidden" name="subj" id="subj" value="p"> <input type="hidden" name="subj" id="subj" value="p">
<textarea name="wtext" id="wtext"></textarea><br> <textarea name="wtext" id="wtext"></textarea><br>
<div id="fileList" class="mt-3"></div>
<p id="statusSend" style="display: none;">Ошибка</p> <p id="statusSend" style="display: none;">Ошибка</p>
<div class="cmt-submit"><input type="submit" value="Добавить комментарий" id="sbmt">&ensp;&emsp;Ctrl + Enter <div class="cmt-submit"><input type="submit" value="Добавить комментарий" id="sbmt"><button style="display: inline;" type="button" id="attachFile"><i class='bx bx-paperclip bx-rotate-90' ></i></button>
</div> </div>
</form> </form>
<?php } else {
echo 'Комментарии могут оставлять только пользователи с подтверждённой почтой.';
}
} else {
echo 'Комментарии могут оставлять только зарегистрированные пользователи.';
}
?>
</div> </div>
</div> </div>
</div> </div>
<script>
document.addEventListener("DOMContentLoaded", function () {
const form = document.getElementById("f1");
if (!form) {
console.error("Форма #f1 не найдена!");
return;
}
const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.name = "filebody"; // Устанавливаем имя filebody
fileInput.style.display = "none";
form.appendChild(fileInput); // Добавляем input внутрь формы
const button = document.getElementById("attachFile");
const fileList = document.getElementById("fileList");
button.addEventListener("click", function () {
fileInput.click();
});
fileInput.addEventListener("change", function () {
const file = fileInput.files[0];
if (!file) return;
const maxSize = 100 * 1024 * 1024; // 100 MB
const forbiddenExtensions = [".html", ".php", ".htm", ".exe", ".com", ".cmd", ".bash", ".sh"];
const fileName = file.name.toLowerCase();
const fileSize = file.size;
if (fileSize > maxSize) {
alert("Файл превышает 100 МБ.");
return;
}
if (forbiddenExtensions.some(ext => fileName.endsWith(ext))) {
alert("Расширение не поддерживается.");
return;
}
const fileItem = document.createElement("div");
fileItem.setAttribute("style", "border:solid 1px #bbb; width:max-content; font-size: 12px; padding:3px 10px 3px; margin-bottom:13px; background-color:#e2e2e2");
fileItem.textContent = file.name;
const removeBtn = document.createElement("a");
removeBtn.classList.add("compl");
removeBtn.setAttribute("style", "display: inline-block; margin-left: 5px; color:#292929; cursor: pointer;");
removeBtn.textContent = "";
removeBtn.addEventListener("click", function () {
fileItem.remove();
fileInput.value = "";
});
fileItem.appendChild(removeBtn);
fileList.appendChild(fileItem);
});
});
</script>
<?php } else { ?> <?php } else { ?>
<div class="p0" id="pp-item-comments"> <div class="p0" id="pp-item-comments">
@ -663,67 +743,64 @@ if ($photo->i('id') !== null) {
</tbody> </tbody>
</table> </table>
<script> <script>
$(document).ready(function() { $(document).ready(function() {
$('#f1').submit(function(e) { $('#f1').submit(function(e) {
e.preventDefault(); e.preventDefault();
$.ajax({
type: "POST",
url: '/api/photo/comment',
data: $(this).serialize(),
success: function(response) {
var jsonData = JSON.parse(response);
if (jsonData.errorcode == "1") {
$('#statusSend').css({
display: 'block',
color: 'red'
});
$('#statusSend').text('Комментарий некорректен');
//Notify.noty('danger', 'Комментарий неккоректен');
//$("#result").html("<div class='alert alert-dangernew container mt-5' role='alert'>Неправильная почта или пароль!</div>");
} else if (jsonData.errorcode == "2") {
$('#statusSend').css({
display: 'block',
color: 'yellow'
});
$('#statusSend').text('Пожалуйста, подождите...');
//Notify.noty('warning', 'Пожалуйста, подождите...');
setTimeout(function() {
window.location.replace(jsonData.twofaurl);
}, 1000);
} else if (jsonData.errorcode == "0") {
$('#wtext').val('');
$('#statusSend').css({
display: 'block',
color: 'green'
});
$('#statusSend').text('Комментарий отправлен!');
//Notify.noty('success', 'Комментарий отправлен!');
//$("#result").html("<div class='alert alert-successnew container mt-5' role='alert'>Успешный вход!</div>");
$.ajax({
var formData = new FormData(this); // Собираем данные из формы, включая filebody
type: "POST", $.ajax({
url: "/api/photo/getcomments/<?= $id ?>", type: "POST",
processData: false, url: "/api/photo/comment",
async: true, data: formData,
success: function(r) { processData: false, // Не обрабатывать данные (важно для файлов)
$('#posts').html(r) contentType: false, // Не устанавливать заголовок Content-Type (браузер сделает сам)
success: function(response) {
var jsonData = JSON.parse(response);
if (jsonData.errorcode == "1") {
$('#statusSend').css({
display: 'block',
color: 'red'
}).text('Комментарий некорректен');
} else if (jsonData.errorcode == "2") {
$('#statusSend').css({
display: 'block',
color: 'yellow'
}).text('Пожалуйста, подождите...');
setTimeout(function() {
window.location.replace(jsonData.twofaurl);
}, 1000);
} else if (jsonData.errorcode == "0") {
$('#wtext').val('');
$('#statusSend').css({
display: 'block',
color: 'green'
}).text('Комментарий отправлен!');
}, $.ajax({
error: function(r) { type: "POST",
console.log(r) url: "/api/photo/getcomments/<?= $id ?>",
} processData: false,
async: true,
}); success: function(r) {
$('#posts').html(r);
} else { },
Notify.noty('danger', 'Неизвестная ошибка'); error: function(r) {
console.log(r);
} }
} });
}); } else {
}); alert('Неизвестная ошибка');
}
},
error: function(err) {
console.error("Ошибка при отправке формы", err);
}
}); });
});
});
function errimg() { function errimg() {
const content = `<center> const content = `<center>

View file

@ -15,6 +15,8 @@ $photo = new \App\Models\Photo($_GET['id']);
<div id="backgr"></div> <div id="backgr"></div>
<table class="tmain"> <table class="tmain">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?> <?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<?php
if ($photo->i('moderated') === 1) { ?>
<tr> <tr>
<td class="main"> <td class="main">
<center> <center>
@ -61,7 +63,19 @@ $photo = new \App\Models\Photo($_GET['id']);
</center> </center>
</td> </td>
</tr> </tr>
<?php } else { ?>
<tr>
<td class="main">
<center>
<h1>Изображение не найдено</h1>
<div class="p20w" style="margin-bottom:20px; padding:10px 30px">
<img src="/static/img/pnp.jpg" alt="Пусто" width="400" height="205" border="0">
<p>Изображения с таким номером нет на сайте.<br />Может быть, его здесь никогда и не было.<br />Если Вы уверены, что что-то здесь всё-таки было, значит, администратор по каким-то причинам это удалил.</p>
</div>
</center>
</td>
</tr>
<?php } ?>
<tr> <tr>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Footer.php'); ?> <?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Footer.php'); ?>
</tr> </tr>

View file

@ -43,6 +43,9 @@ $user = new User(Auth::userid());
var pub_pid = 0; var pub_pid = 0;
</script> </script>
<td class="main"> <td class="main">
<?php if (NGALLERY['root']['registration']['emailverify'] != true || $user->i('status') === 3) {
die('Чтобы публиковать Фотографии и Видео, нужно подтвердить почту.');
} ?>
<h1>Предложить медиа на публикацию</h1> <h1>Предложить медиа на публикацию</h1>
<p>Ваш текущий индекс загрузки: <b><?= $user->i('uploadindex') ?></b></p> <p>Ваш текущий индекс загрузки: <b><?= $user->i('uploadindex') ?></b></p>

View file

@ -98,6 +98,7 @@ if (Auth::userid() > 0) {
<input type="button" id="regbtn" class="mf-button-wide" style="margin-top:15px" value="Зарегистрироваться"> <input type="button" id="regbtn" class="mf-button-wide" style="margin-top:15px" value="Зарегистрироваться">
<p>Регистрируясь на сервере <?= NGALLERY['root']['title'] ?>, вы <a href="/rules">принимаете его правила.</a></p> <p>Регистрируясь на сервере <?= NGALLERY['root']['title'] ?>, вы <a href="/rules">принимаете его правила.</a></p>
<p><b><a href="/tour">Вы можете пройти экскурсию по сайту.</a></b></p>
</form><br><br> </form><br><br>
<br> <br>

View file

@ -0,0 +1,36 @@
<?php
use \App\Services\{Auth, DB, Date};
use \App\Models\User;
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/LoadHead.php'); ?>
</head>
<body>
<div id="backgr"></div>
<table class="tmain">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<td class="main">
<h1>Спасибо, ваша почта подтверждена.</h1>
</td>
</tr
<tr>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Footer.php'); ?>
</tr>
</table>
</body>
</html>

843
views/pages/Tour.php Normal file
View file

@ -0,0 +1,843 @@
<?php
use App\Services\{Router, Auth};
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/LoadHead.php'); ?>
</head>
<body>
<div id="backgr"></div>
<table class="tmain">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<div id="backgr"></div>
<style>
.tablinks {
color: #000;
}
#tour {
background-color: #f7f7F7;
padding: 0px;
overflow: hidden ! important;
_height: 1% ! important;
}
.welcome {
background-color: #fff;
padding: 10px;
padding-right: 50px;
border: 1px solid #ccc;
}
h4 {
border-bottom: solid 1px #b9c4da;
margin: 0px;
padding: 0px 0px 4px;
font-size: 15px;
}
h6 {
color: #45668E;
font-size: 13px;
padding-bottom: 3px;
height: 32px;
width: auto;
}
h2 {
color: #45668E;
font-size: 35px;
padding-bottom: 3px;
width: auto;
border-bottom: 1px solid #DAE1E8;
}
.correctIt {
font-size: 11px;
color: #777;
font-weight: normal;
float: right;
}
p.wel {
padding-left: 50px;
font-size: 11px;
background: #fff;
}
#auth {
background: #f7f7F7;
}
.wLabel {
float: left;
width: 100px;
padding-top: 4px;
font-weight: bold;
color: #777;
text-align: right;
padding-right: 16px;
}
p.big {
font-size: 12px;
text-align: center;
}
.tour {
background: #F9F6E7;
border: 1px solid #BEAD61;
padding: 8px 25px;
width: 205px;
text-align: center;
color: #000;
font-size: 12px;
margin: 10px auto;
cursor: hand;
cursor: pointer;
}
.tour div {
font-size: 11px;
color: #000;
}
a.noUnd:hover {
text-decoration: none;
}
.helpNav {
margin: 4px 0px;
padding: 4px 6px;
background: #DAE1E8;
border-top: 1px solid #B7BEC6;
width: 5.3em;
font-size: 11px;
text-decoration: none;
color: #2B587A;
cursor: hand;
cursor: pointer;
}
.helpNav a {
text-decoration: none;
}
.selled {
background-color: #B8C4CF;
}
* {
box-sizing: border-box
}
.rightNav {
border: 0px;
width: 140px;
padding-left: 6px;
float: right;
}
.rightNav h1 {
border: 0px;
background: #EAEAEA;
font-weight: bold;
font-size: 11px;
padding: 4px 5px;
}
.rightLinks {
margin-bottom: 10px;
}
.rightLinks div {
padding: 4px 6px 4px 5px;
margin: 1px;
}
.rightLinks .active {
background: #fff;
}
.rightLinks .active a {
cursor: default;
color: #000;
font-weight: bold;
}
.rightLinks .active a:hover {
cursor: default;
text-decoration: none;
}
.rightLinks img {
vertical-align: bottom;
margin-right: 5px;
}
/* Style the tab */
.tab {
float: right;
width: 140px;
}
.tab:hover {
background: none;
}
/* Style the buttons inside the tab */
.tab button {
display: block;
background-color: inherit;
width: 138px;
height: 24px;
border: none;
margin-bottom: 5px;
outline: none;
text-align: left;
cursor: pointer;
background: none;
font-size: 10px;
padding: 2px 0px 3px;
font-family: Tahoma, sans-serif !important;
}
/* Create an active/current "tab button" class */
.tab button.active {
background-color: #fff;
cursor: default;
color: #000;
font-weight: bold;
}
.tab button.hover {
background: none;
}
/* Style the tab content */
.tabcontent {
float: left;
padding: 0px 12px;
background: #fff;
width: 77%;
}
.tabcontent img {
margin: auto;
}
.tabicon {
width: 16px;
height: 16px;
display: inline;
margin-right: 1px;
}
.player {
display: flex;
align-items: center;
gap: 10px;
background: #f4f4f4;
padding: 10px;
border-radius: 5px;
width: 500px;
}
.progress {
flex-grow: 1;
height: 5px;
background: #ccc;
position: relative;
cursor: pointer;
width: 100px;
border-radius: 3px;
}
.progress span {
position: absolute;
height: 100%;
width: 0%;
background: #666;
border-radius: 3px;
}
.slider {
position: absolute;
top: -3px;
height: 10px;
width: 10px;
background: #333;
border-radius: 50%;
transform: translateX(-50%);
}
.time {
font-size: 12px;
color: #333;
}
</style>
<tr>
<td class="main">
<div class="player">
<button id="playPause"></button>
<div class="info">
<strong>Неизвестен</strong> Tele 2 - X_й дозвонишься.mp3
</div>
<div class="progress" id="progressBar">
<span></span>
<div class="slider" id="slider"></div>
</div>
<span class="time" id="time">00:00 / 00:06</span>
</div>
<audio id="audio" src="/static/kolya.mp3"></audio>
<script>
const audio = document.getElementById("audio");
const playPause = document.getElementById("playPause");
const progressBar = document.getElementById("progressBar");
const progress = progressBar.querySelector("span");
const timeDisplay = document.getElementById("time");
playPause.addEventListener("click", () => {
if (audio.paused) {
audio.play();
playPause.textContent = "";
} else {
audio.pause();
playPause.textContent = "";
}
});
audio.addEventListener("timeupdate", () => {
const currentTime = audio.currentTime;
const duration = audio.duration;
const progressPercent = (currentTime / duration) * 100;
progress.style.width = progressPercent + "%";
const formatTime = (time) => {
const minutes = Math.floor(time / 60);
const seconds = Math.floor(time % 60).toString().padStart(2, '0');
return `${minutes}:${seconds}`;
};
timeDisplay.textContent = `${formatTime(currentTime)} / ${formatTime(duration)}`;
});
progressBar.addEventListener("click", (e) => {
const rect = progressBar.getBoundingClientRect();
const clickX = e.clientX - rect.left;
const progressWidth = rect.width;
const newTime = (clickX / progressWidth) * audio.duration;
audio.currentTime = newTime;
});
</script>
<div class="wrap2">
<div class="wrap1">
<div id="auth" class="page-wrap">
<div class="page_content">
<link rel="stylesheet" href="/assets/packages/static/openvk/css/tour.css?mod=1hrjjis" integrity="sha384-X/G3xXjBuUDvjn9+KLt4u5gq4hAcPsygJjdF39O24oYh/ZcAzDeMH8PYftnIaan0" crossorigin="anonymous">
<div id="tour">
<div class="rightNav">
<h1>Экскурсия по сайту</h1>
<div class="rightLinks">
<div class="tab">
<button class="tablinks active" onclick="eurotour(event, 'start')" id="defaultOpen">
<div class="tabicon"><img src="https://ovk.to/assets/packages/static/openvk/img/icons/1.svg" width="16" height="16"></div>Начало
</button>
<button class="tablinks" onclick="eurotour(event, 'profile')">
<div class="tabicon"><img src="https://ovk.to/assets/packages/static/openvk/img/icons/2.svg" width="16" height="16"></div>Профиль
</button>
<button class="tablinks" onclick="eurotour(event, 'photos')">
<div class="tabicon"><img src="https://ovk.to/assets/packages/static/openvk/img/icons/3.svg" width="16" height="16"></div>Фотографии и Видео
</button>
</div>
</div>
</div>
<div id="start" class="tabcontent" style="display: block;">
<h2>С чего начать?</h2>
<ul class="listing">
<li><span>Регистрация аккаунта является самым первым и основным этапом в начале вашего пути на данном сайте.</span></li>
<li><span>Для регистрации вам потребуется ввести Логин, E-mail и пароль.</span></li>
<li><span>В качестве логина для входа на сайт, Вы можете использовать свой E-mail или никнейм, указанный при регистрации.</span></li>
</ul>
<img src="/static/img/tour1.png" width="440">
<p class="big">Регистрируясь на сайте, вы соглашаетесь с <a href="/rules">правилами сайта</a></p>
<div style="margin-top:10px; padding-left:175px">
</div>
<br>
</div>
<div id="profile" class="tabcontent" style="display: none;">
<h2>Ваш профиль</h2>
<ul class="listing">
<li><span>Для взаимодействия с сайтом, у вас появляется профиль.</span></li>
<li><span>Ваш профиль виден всем пользователям и даже гостям сайта. <b>В целях приватности и безопасности, пожалуйста, воздержитесь от публикации личной информации в профиле.</b></span></li>
<li><span>На Вас, как и Вы на других пользователей можете подписываться, чтобы следить за обновлениями во вкладке <b><a href="/fav_authors">Фотографии избранных авторов</a></b>.</span></li>
</ul>
<img src="/static/img/tour2.png" width="440">
<br>
</div>
<div id="photos" class="tabcontent" style="display: none;">
<h2>Фотографии и Видео</h2>
<ul class="listing">
<li><span>Фотографии и Видео это неотъемлемая часть сайта, на которой строится вся идея портала <?=NGALLERY['root']['title']?>.</span></li>
<li><span>На главной странице размещаются последние 30 фотографий и топ 10 фотографий по просмотрам за 24 часа.</span></li>
</ul>
<img src="/static/img/tour3.png" width="440">
<br>
</div>
<div id="search" class="tabcontent" style="display: none;">
<h2>Поиск</h2>
<ul class="listing">
<li><span>Раздел "Поиск" позволяет искать пользователей и группы.</span></li>
<li><span>Данный раздел сайта со временем будет улучшаться.</span></li>
</ul>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/search.png" width="440">
<ul class="listing">
<li><span>Для начала поиска нужно знать имя (или фамилию) пользователя; а если ищете группу, то нужно знать её название.</span></li>
</ul>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/search2.png" width="440">
<h2>Быстрый поиск</h2>
<ul class="listing">
<li><span>Если вы хотите как-либо сэкономить время, то строка поиска доступна и в шапке сайта</span></li>
</ul>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/search_h.png" width="440">
<br>
</div>
<div id="videos" class="tabcontent" style="display: none;">
<h2>Загружайте и делитесь видео со своими друзьями!</h2>
<ul class="listing">
<li><span>Вы можете загружать неограниченное количество видеозаписей и клипов</span></li>
<li><span>Раздел "Видеозаписи" регулируется настройками приватности</span></li>
</ul>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/videos.png" width="440">
<p class="big">Видео можно загружать минуя раздел "Видеозаписи" через обычное прикрепление к новой записи на стене:</p>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/videos_a.png" width="440">
<h2>Импортирование видео с YouTube</h2>
<ul class="listing">
<li><span>Кроме загрузки видео напрямую, сайт поддерживает и встраивание видео из YouTube</span></li>
</ul>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/videos_y.png" width="440">
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/videos_w.png" width="440">
<br>
</div>
<div id="audios" class="tabcontent" style="display: none;">
<h2>Слушайте аудиозаписи</h2>
<ul class="listing">
<li><span>Вы можете слушать аудиозаписи в разделе "Мои Аудиозаписи"</span></li>
<li><span>Этот раздел также регулируется настройками приватности</span></li>
<li><span>Самые прослушиваемые песни находятся во вкладке "Популярное", а недавно загруженные во вкладке "Новое"</span></li>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/audios.png" width="440">
</ul>
<ul class="listing">
<li><span>Чтобы добавить песню в свою коллекцию, наведите на неё и нажмите на плюс. Найти нужную песню можно в поиске</span></li>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/audios_search.png" width="440">
<li><span>Если вы не можете найти нужную песню, вы можете загрузить её самостоятельно</span></li>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/audios_upload.png" width="440">
</ul>
<p class="big"><b>Важно:</b> песня не должна нарушать авторские права</p>
<h2>Создавайте плейлисты</h2>
<ul class="listing">
<li><span>Вы можете создавать сборники треков во вкладке "Мои плейлисты"</span></li>
<li><span>Можно также добавлять чужие плейлисты в свою коллекцию</span></li>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/audios_playlists.png" width="440">
</ul>
<br>
</div>
<div id="news" class="tabcontent" style="display: none;">
<h2>Следите за тем, что пишут ваши друзья</h2>
<ul class="listing">
<li><span>Раздел "Мои Новости" разделяется на два типа: локальная лента и глобальная лента</span></li>
<li><span>В локальной ленте будут показываться новости только ваших друзей и групп</span></li>
</ul>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/local_news.png" width="440">
<p class="big">Никакой системы рекомендаций. <b>Свою ленту новостей формируете только вы.</b></p>
<br>
</div>
<div id="news_global" class="tabcontent" style="display: none;">
<h2>Следите за тем, какие темы обсуждают на сайте</h2>
<ul class="listing">
<li><span>В глобальной ленте новостей будут показываться записи всех пользователей сайта и групп</span></li>
<li><span>Просмотр данного раздела может не рекомендоваться для чувствительных и ранимых людей</span></li>
</ul>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/news_global.png" width="440">
<p class="big">Дизайн глобальной ленты по дизайну никак не отличается от локальной</p>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/poll.png" width="440">
<p class="big">В ленте есть множество типов контента: начиная от обычных фото и видео, и заканчивая анонимными постами и опросами</p>
<br>
</div>
<div id="groups" class="tabcontent" style="display: none;">
<h2>Создавайте группы!</h2>
<ul class="listing">
<li><span>На сайте уже имеются тысячи групп, посвящённые различным темам и каким-либо фанатским объединениям</span></li>
<li><span>Вы можете присоединяться к любой группе. А если не нашли подходящую, то можно создавать и свою</span></li>
<li><span>Каждая группа имеет свой раздел вики-страниц, фотоальбомов, блок ссылок и обсуждений</span></li>
</ul>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/groups.png" width="440">
<p class="big">Раздел "Мои Группы" находится в левом меню сайта</p>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/groups_view.png" width="440">
<p class="big">Пример сообщества</p>
<h2>Управляйте своей группой вместе с другом</h2>
<ul class="listing">
<li><span>Управление группой осуществляется в разделе "Редактировать группу" под аватаром сообщества</span></li>
<li><span>Создайте команду администраторов из обычных участников или тех, кому вы доверяете</span></li>
<li><span>Вы можете скрыть нужного Вам администратора, чтобы он нигде не показывался в пределах вашей группы</span></li>
</ul>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/groups_admin.png" width="440">
<p class="big">Группы часто представляют собой реальные организации, члены которых хотят оставаться на связи со своей аудиторией</p>
<br>
</div>
<div id="events" class="tabcontent" style="display: none;">
<h2>Упс</h2>
<ul class="listing">
<li><span>Я был бы очень рад сделать туториал по этому разделу, но раздел находится на этапе разработки. А сейчас мы пока этот раздел туториала пропустим и пойдём дальше...</span></li>
</ul>
<br>
</div>
<div id="themes" class="tabcontent" style="display: none;">
<h2>Темы оформления</h2>
<ul class="listing">
<li><span>После регистрации, в качестве оформления у вас будет установлена стандартная тема</span></li>
<li><span>Некоторых новых пользователей может слегка отпугнуть нынешняя стоковая тема, которая веет совсем уж древностью</span></li>
<li><span><b>Но не беда:</b> Вы можете создать свою тему для сайта, ознакомившись с <a href="https://docs.ovk.to/">документацией</a> или выбрать уже существующую из каталога</span></li>
</ul>
<center><img src="https://ovk.to/assets/packages/static/openvk/img/tour/theme_picker.png"></center>
<p class="big">Каталог тем доступен в разделе "Мои Настройки" во вкладке "Интерфейс" </p><br>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/theme3.png" width="460">
<table cellspacing="5" border="0">
<tbody>
<tr>
<td><img src="https://ovk.to/assets/packages/static/openvk/img/tour/theme1.png" style="float:left;" width="220"></td>
<td><img src="https://ovk.to/assets/packages/static/openvk/img/tour/theme2.png" style="float:right;" width="220"></td>
</tr>
</tbody>
</table>
<br>
<center><img src="/https://ovk.to/assets/packages/static/openvk/img/tour/wordart.png" width="65%"></center>
<br>
</div>
<div id="customization" class="tabcontent" style="display: none;">
<h2>Фон профиля и группы</h2>
<ul class="listing">
<li><span>Вы можете установить два изображения в качестве фона вашей страницы</span></li>
<li><span>Они будут отображаться по бокам у тех, кто зайдёт на вашу страницу</span></li>
</ul>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/backdrop.png" width="440">
<p class="big">Страница установки фона</p><br>
<ul class="listing">
<li><span><b>Совет:</b> перед установкой фона, поэкспериментируйте с разметкой: попробуйте отзеркалить будущую фоновую картинку, или вообще просто создайте красивый градиент</span></li>
</ul>
<br>
<table cellspacing="5" border="0">
<tbody>
<tr>
<td><img src="https://ovk.to/assets/packages/static/openvk/img/tour/backdrop_ex.png" width="440"></td>
</tr>
<tr>
<td><img src="https://ovk.to/assets/packages/static/openvk/img/tour/backdrop_ex1.png" width="440"></td>
</tr>
<tr>
<td><img src="https://ovk.to/assets/packages/static/openvk/img/tour/backdrop_ex2.png" width="440"></td>
</tr>
</tbody>
</table>
<p class="big">Примеры страниц с установленным фоном</p><br>
<p class="big">С помощью этой возможности вы можете добавить своему профилю больше индивидуальности</p>
<h2>Аватары</h2>
<ul class="listing">
<li><span>Вы можете задать вариант показа аватара пользователя: стандартное, закруглённые и квадратные (1:1)</span></li>
<li><span>Данные настройки будут видны только вам</span></li>
</ul>
<center><img src="https://ovk.to/assets/packages/static/openvk/img/tour/avatar_picker.png"></center><br>
<table cellspacing="5" border="0">
<tbody>
<tr>
<td><img src="https://ovk.to/assets/packages/static/openvk/img/tour/avatars_def.png" style="float:left;" width="220"></td>
<td><img src="https://ovk.to/assets/packages/static/openvk/img/tour/avatars_round.png" style="float:right;" width="220"></td>
</tr>
</tbody>
</table><br>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/avatars_quad.png" width="440">
<h2>Редактирование левого меню</h2>
<ul class="listing">
<li><span>При необходимости вы можете скрыть ненужные разделы сайта</span></li>
<li><span><b>Напоминание: </b>Разделы первой необходимости (Моя Страница; Мои Друзья; Мои Ответы; Мои Настройки) скрыть нельзя</span></li>
</ul>
<table cellspacing="5" border="0">
<tbody>
<tr>
<td><img src="https://ovk.to/assets/packages/static/openvk/img/tour/leftmenu.png" style="float:left;" width="220"></td>
<td><img src="https://ovk.to/assets/packages/static/openvk/img/tour/leftmenu2.png" style="float:right;" width="220"></td>
</tr>
</tbody>
</table>
<h2>Вид постов</h2>
<ul class="listing">
<li><span>Если надоел старый дизайн стены, который был в некогда популярном оригинальном ВКонтакте.ру, то вы всегда можете изменить вид постов на Микроблог</span></li>
<li><span>Вид постов можно менять между двумя вариантами в любое время</span></li>
<li><span><b>Обратите внимание</b>, что если выбран старый вид отображения постов, то последние комментарии подгружаться не будут</span></li>
</ul>
<center><img src="https://ovk.to/assets/packages/static/openvk/img/tour/wall_pick.png"></center><br>
<table cellspacing="5" border="0">
<tbody>
<tr>
<td><img src="https://ovk.to/assets/packages/static/openvk/img/tour/wall_old.png" style="float:left;" width="220">
<br>
<p class="big" Старый="" вид="" постов<="" p=""></p>
</td>
<td><img src="https://ovk.to/assets/packages/static/openvk/img/tour/wall_new.png" style="float:right;" width="220">
<br>
<p class="big">Микроблог</p>
</td>
</tr>
</tbody>
</table>
<br>
<br>
</div>
<div id="vouchers" class="tabcontent" style="display: none;">
<h2>Ваучеры</h2>
<ul class="listing">
<li><span>Ваучер в OpenVK это что-то вроде промокода на добавление какой-либо валюты (проценты рейтинга, голосов и так далее)</span></li>
<li><span>Подобные купоны создаются по каким-либо значимым событиям и праздникам. Следите за <a href="https://t.me/openvk">Telegram-каналом</a> OpenVK</span></li>
</ul>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/vouchers.png" width="440">
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/vouchers_type.png" width="440">
<p class="big">Ваучеры состоят из 24 цифр и букв</p><br>
<ul class="listing">
<li><span>После активации какого-либо ваучера, заданная администраторами валюта будет перечислена в вашу пользу</span></li>
<li><span><b>Помните: </b>Все ваучеры имеют ограниченный срок активации</span></li>
</ul>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/vouchers_ok.png" width="440">
<p class="big">Успешная активация (например, нам зачислили 100 голосов)</p><br>
<p class="big"><b>Внимание: </b>После активации ваучера на вашу страницу, тот же самый ваучер нельзя будет активировать повторно</p><br>
<br>
<br>
</div>
<div id="mobile" class="tabcontent" style="display: none;">
<h2>Мобильная версия</h2>
<ul class="listing">
<li><span>На данный момент мобильной веб-версии сайта пока нет, но зато есть мобильное приложение для Android</span></li>
<li><span>OpenVK Legacy - это мобильное приложение OpenVK для ретро-устройств на Android с дизайном ВКонтакте 3.0.4 из 2013 года</span></li>
<li><span>Минимально поддерживаемой версией является Android 2.1 Eclair, то есть аппараты времён начала 2010-ых вполне пригодятся</span></li>
</ul>
<table cellspacing="5" border="0">
<tbody>
<tr>
<td><img src="https://ovk.to/assets/packages/static/openvk/img/tour/app1.png" style="float:left;" width="210"></td>
<td><img src="https://ovk.to/assets/packages/static/openvk/img/tour/app2.png" style="float:right;" width="210"></td>
</tr>
</tbody>
</table>
<table cellspacing="5" border="0">
<tbody>
<tr>
<td><img src="https://ovk.to/assets/packages/static/openvk/img/tour/app3.png" width="425"></td>
</tr>
</tbody>
</table>
<p class="big">Скриншоты приложения</p><br>
<h2>Где это можно скачать?</h2>
<ul class="listing">
<li><span>Релизные версии скачиваются через официальный репозиторий F-Droid</span></li>
<li><span>Если вы являетесь бета-тестировщиком приложения, то новые версии приложения выкладываются в отдельный канал обновления</span></li>
<li><span><b>Важно: </b>Приложение может иметь различные баги и недочёты, об ошибках сообщайте в <a href="/app">официальную группу приложения</a></span></li>
</ul>
<img src="https://ovk.to/assets/packages/static/openvk/img/tour/app4.jpeg" width="440">
<br>
<br>
<p class="big">На этом экскурсия по сайту завершена.</p><br>
<br>
</div>
<script src="/assets/packages/static/openvk/js/tour.js?mod=1hrjqlm" integrity="sha384-TOd8nhYT6/RcnW0M5F75ZFeWeGPLU1lh6LyZ3xi8iEIIVd43udMi7MSs6M1Kpab5" crossorigin="anonymous"></script>
</div>
</div>
</div>
</div>
</div>
</td>
</tr>
<tr>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Footer.php'); ?>
</tr>
</table>
<script>
function eurotour(evt, step) {
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
document.getElementById(step).style.display = "block";
evt.currentTarget.className += " active";
}
// Get the element with id="defaultOpen" and click on it
document.getElementById("defaultOpen").click();
</script>
</body>
</html>

View file

@ -1,95 +1,69 @@
<?php <html lang="fr">
$rand = mt_rand(1, 12);
if ($rand === 1) {
$text = 'Что-то грядёт.';
} else if ($rand === 2) {
$text = 'Может, пора запустить СТТС Собаки?';
} else if ($rand === 3) {
$text = 'Не снижая обороты.';
} else if ($rand === 4) {
$text = 'Мы соскучились по твоим фотографиям.';
} else if ($rand === 5) {
$text = 'Хм-м...';
} else if ($rand === 6) {
$text = 'Весьма очень даже.';
} else if ($rand === 7) {
$text = 'Не забудь взять царских припасов с собой.';
} else if ($rand === 8) {
$text = 'Бобровы будут гордиться.ю';
} else if ($rand === 9) {
$text = 'Нельзя было стучаться, что-ли?';
} else if ($rand === 10) {
$text = 'Ха-ха.';
} else if ($rand === 11) {
$text = 'Недурно.';
} else if ($rand === 12) {
$text = '...';
}
?>
<!DOCTYPE html>
<html lang="ru">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Таймер обратного отсчета</title> <title>Mini Vidéoplayer</title>
<style> <style>
@import url('https://fonts.googleapis.com/css2?family=Inter+Tight:ital,wght@0,100..900;1,100..900&display=swap'); body { font-family: Arial, sans-serif; text-align: center; }
.player { width: 60%; margin: auto; position: relative; }
body { video { width: 100%; display: block; }
font-family: Inter Tight !important; .controls { display: flex; align-items: center; justify-content: space-between; padding: 10px; background: #333; color: white; }
} .controls button { background: none; border: none; color: white; cursor: pointer; }
body { .progress-bar { width: 100%; height: 5px; background: gray; position: relative; cursor: pointer; }
font-family: Arial, sans-serif; .progress { width: 0%; height: 100%; background: red; position: absolute; }
text-align: center;
margin-top: 100px;
}
#countdown {
font-size: 100px;
color: #333;
}
</style> </style>
</head> </head>
<body> <body>
<center><img src="/static/img/sttslogo.png" width="500"></center> <div class="player">
<h1><?=$text?></h1> <video id="video" src="video.mp4"></video>
<div id="countdown">00:00:00</div> <div class="controls">
<button id="playPause"></button>
<input type="range" id="volume" min="0" max="1" step="0.1" value="1">
<button id="fullscreen"></button>
</div>
<div class="progress-bar" id="progressBar">
<div class="progress" id="progress"></div>
</div>
</div>
<script> <script>
function updateCountdown() { const video = document.getElementById('video');
const now = new Date(); const playPause = document.getElementById('playPause');
const nowUtc = new Date(now.getTime() + now.getTimezoneOffset() * 60000); // Преобразуем текущее время в UTC const volume = document.getElementById('volume');
const progressBar = document.getElementById('progressBar');
const progress = document.getElementById('progress');
const fullscreen = document.getElementById('fullscreen');
// Определяем текущее время в UTC+3 (МСК) playPause.addEventListener('click', () => {
const nowMoscow = new Date(nowUtc.setHours(nowUtc.getUTCHours() + 3)); if (video.paused) {
video.play();
// Устанавливаем время окончания на 17:00 текущего дня по МСК playPause.textContent = '⏸';
let targetTime = new Date(nowMoscow.getFullYear(), nowMoscow.getMonth(), nowMoscow.getDate(), 17, 0, 0);
// Если текущее время уже прошло 17:00, устанавливаем на следующий день
if (nowMoscow >= targetTime) {
targetTime.setDate(targetTime.getDate() + 1);
}
const timeDifference = targetTime - nowMoscow;
if (timeDifference <= 0) {
location.reload(); // Перезагрузить страницу по истечению времени
} else { } else {
const hours = Math.floor((timeDifference / (1000 * 60 * 60)) % 24); video.pause();
const minutes = Math.floor((timeDifference / (1000 * 60)) % 60); playPause.textContent = '▶';
const seconds = Math.floor((timeDifference / 1000) % 60);
document.getElementById('countdown').textContent =
`${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
} }
} });
setInterval(updateCountdown, 1000); // Обновляем каждую секунду volume.addEventListener('input', () => {
updateCountdown(); // Начальная установка video.volume = volume.value;
});
video.addEventListener('timeupdate', () => {
const progressPercent = (video.currentTime / video.duration) * 100;
progress.style.width = progressPercent + '%';
});
progressBar.addEventListener('click', (e) => {
const newTime = (e.offsetX / progressBar.offsetWidth) * video.duration;
video.currentTime = newTime;
});
fullscreen.addEventListener('click', () => {
if (!document.fullscreenElement) {
video.requestFullscreen();
} else {
document.exitFullscreen();
}
});
</script> </script>
</body> </body>
</html> </html>