Файл: pages/social/ticket.php
Строк: 319
<?php
// Physical module map v50.6.
if (!defined('GAME_ROOT')) define('GAME_ROOT', dirname(__DIR__, 2));
chdir(GAME_ROOT);
if (PHP_SAPI !== 'cli') { $_SERVER['PHP_SELF']='/ticket.php'; $_SERVER['SCRIPT_NAME']='/ticket.php'; }
/* Техподдержка PHP 8.4/PDO: user + staff inbox. by Метриум (Стэлп) */
require_once './system/common.php';
require_once './system/functions.php';
require_once './system/user.php';
if(!$user){ header('Location:/'); exit; }
function ticket_topic_label(string $type): string {
return match($type){'sms'=>'Вопросы об оплате с помощью SMS','payment'=>'Вопросы об оплате прочими способами',default=>'Общие вопросы'};
}
function ticket_clean(string $s,int $max=2000): string { return trim(mb_substr(strip_tags($s),0,$max,'UTF-8')); }
function ticket_status(string $s): string { return match($s){'close'=>'Закрыт','read'=>'Есть ответ','user'=>'Ожидает ответа администрации',default=>'Новое'}; }
function ticket_redirect(string $url): never { header('Location: '.$url); exit; }
$mode=(string)($_GET['mode']??'home');
$type=(string)($_GET['type']??'');
$id=max(0,(int)($_GET['id']??0));
$allowed=['general','sms','payment'];
if($type!==''&&!in_array($type,$allowed,true)) $type='';
$isStaff=(int)($user['access']??0)>0;
// One-time compatibility for legacy installations where ticket titles were only VARCHAR(25).
if(function_exists('game_meta_get') && (int)game_meta_get('ticket_schema','0')<2){
$col=db_fetch_one("SHOW COLUMNS FROM `ticket` LIKE 'title'");
if($col && preg_match('/varchar\((\d+)\)/i',(string)($col['Type']??''),$m) && (int)$m[1]<120){
db_query("ALTER TABLE `ticket` MODIFY COLUMN `title` varchar(120) NOT NULL");
}
game_meta_set('ticket_schema','2');
}
$isStaffMode=$isStaff && in_array($mode,['viev_all','view_all','admin_view'],true);
if(($_SERVER['REQUEST_METHOD']??'GET')==='POST'){
security_require_csrf();
$action=(string)($_POST['action']??'');
if($isStaff && in_array($action,['admin_reply','admin_close','admin_reopen'],true)){
$ticketId=max(1,(int)($_POST['ticket_id']??$id));
$tik=db_fetch_one('SELECT * FROM `ticket` WHERE `id`=:i LIMIT 1',['i'=>$ticketId]);
if(!$tik){ $_SESSION['ticket_notice']='Обращение не найдено.'; ticket_redirect('/adm/support/'); }
if($action==='admin_reply'){
$text=ticket_clean((string)($_POST['body']??''),2000);
if(mb_strlen($text,'UTF-8')<2){ $_SESSION['ticket_notice']='Введите ответ.'; ticket_redirect('/ticket/?mode=admin_view&id='.$ticketId); }
db_prepare('INSERT INTO `ticket_answer` (`type`,`text`,`ticket`) VALUES (?,?,?)',['admin',$text,$ticketId]);
db_execute("UPDATE `ticket` SET `status`='read' WHERE `id`=:i",['i'=>$ticketId]);
// System mail gives the player a visible (+) in mail/header.
$msg='Техподдержка ответила на обращение «'.mb_substr((string)$tik['title'],0,80,'UTF-8').'». Откройте раздел техподдержки.';
db_prepare('INSERT INTO `mail` (`from`,`to`,`text`,`time`,`read`) VALUES (0,?,?,?,0)',[(int)$tik['user'],$msg,time()]);
$_SESSION['ticket_notice']='Ответ отправлен.';
} elseif($action==='admin_close'){
db_execute("UPDATE `ticket` SET `status`='close' WHERE `id`=:i",['i'=>$ticketId]);
$_SESSION['ticket_notice']='Обращение закрыто.';
} else {
db_execute("UPDATE `ticket` SET `status`='user' WHERE `id`=:i",['i'=>$ticketId]);
$_SESSION['ticket_notice']='Обращение снова открыто.';
}
ticket_redirect('/ticket/?mode=admin_view&id='.$ticketId);
}
if(!security_honeypot_ok() || !security_rate_limit('ticket:'.(int)$user['id'],8,3600)){
$_SESSION['ticket_notice']='Слишком много обращений. Попробуйте позже.'; ticket_redirect('/ticket/');
}
if($action==='create' && in_array($type,$allowed,true)){
$body='';
if($type==='sms'){
$fields=[
'Ваша страна'=>ticket_clean((string)($_POST['country']??''),100),
'Ваш оператор сотовой связи'=>ticket_clean((string)($_POST['operator']??''),100),
'Номер телефона, с которого вы отправляли SMS'=>ticket_clean((string)($_POST['phone']??''),80),
'Короткий номер, на который вы отправляли SMS'=>ticket_clean((string)($_POST['short_number']??''),50),
'Дата и время отправления SMS'=>ticket_clean((string)($_POST['sent_at']??''),80),
'Текст отправленного SMS'=>ticket_clean((string)($_POST['sent_text']??''),500),
'Текст полученного в ответ SMS'=>ticket_clean((string)($_POST['reply_text']??''),500),
'Содержание'=>ticket_clean((string)($_POST['body']??''),3000),
];
foreach($fields as $k=>$v) if($v!=='') $body.=$k.': '.$v."n";
} else $body=ticket_clean((string)($_POST['body']??''),4000);
if(mb_strlen($body,'UTF-8')<5){ $_SESSION['ticket_notice']='Заполните обращение.'; ticket_redirect('/ticket/?mode=create&type='.$type); }
db_prepare('INSERT INTO `ticket` (`time`,`user`,`title`,`text`,`status`) VALUES (?,?,?,?,?)',[time(),(int)$user['id'],ticket_topic_label($type),$body,'new']);
ticket_redirect('/ticket/?mode=view&id='.(int)db_insert_id());
}
if($action==='reply' && $id>0){
$tik=db_fetch_one('SELECT * FROM `ticket` WHERE `id`=:i AND `user`=:u LIMIT 1',['i'=>$id,'u'=>(int)$user['id']]);
$text=ticket_clean((string)($_POST['body']??''),2000);
if($tik && $tik['status']!=='close' && mb_strlen($text,'UTF-8')>=2){
db_prepare('INSERT INTO `ticket_answer` (`type`,`text`,`ticket`) VALUES (?,?,?)',['user',$text,$id]);
db_execute("UPDATE `ticket` SET `status`='user' WHERE `id`=:i",['i'=>$id]);
}
ticket_redirect('/ticket/?mode=view&id='.$id);
}
}
$title=$isStaffMode?'Техподдержка — обращения':'Тех. поддержка';
require './system/h.php';
$notice=(string)($_SESSION['ticket_notice']??''); unset($_SESSION['ticket_notice']);
?>
<div class="support-ref">
<?php if($notice!==''): ?><div class="support-notice"><?=security_html($notice)?></div><?php endif; ?>
<?php if($isStaffMode && $mode!=='admin_view'):
$status=(string)($_GET['status']??'open');
$where=$status==='closed'?"t.`status`='close'":"t.`status`<>'close'";
$rows=db_prepare("SELECT t.*,u.`login` FROM `ticket` t LEFT JOIN `users` u ON u.`id`=t.`user` WHERE $where ORDER BY FIELD(t.`status`,'new','user','read','close'),t.`time` DESC,t.`id` DESC LIMIT 100")->fetchAll();
?>
<div class="support-title">Обращения игроков</div>
<div class="center"><a href="/adm/support/">Открытые</a> · <a href="/adm/support/?status=closed">Закрытые</a></div>
<?php if(!$rows): ?><div class="support-notice">Обращений в этом разделе нет.</div><?php endif; ?>
<?php foreach($rows as $t): ?>
<a class="support-ticket-row" href="/ticket/?mode=admin_view&id=<?=(int)$t['id']?>"><span class="support-doc">▤</span><b><?=security_html((string)$t['title'])?></b><br><small><?=security_html((string)($t['login']??('Игрок #'.$t['user'])))?> · <?=date('d.m.y H:i',(int)$t['time'])?> · <?=security_html(ticket_status((string)$t['status']))?></small></a>
<?php endforeach; ?>
<a class="support-back" href="/adm/">› В админку</a>
<?php elseif($isStaffMode && $mode==='admin_view'):
$tik=$id>0?db_fetch_one('SELECT t.*,u.`login` FROM `ticket` t LEFT JOIN `users` u ON u.`id`=t.`user` WHERE t.`id`=:i LIMIT 1',['i'=>$id]):null;
if(!$tik): ?><div class="support-notice">Обращение не найдено.</div><a class="support-back" href="/adm/support/">› К обращениям</a>
<?php else: $answers=db_prepare('SELECT * FROM `ticket_answer` WHERE `ticket`=:i ORDER BY `id` ASC',['i'=>$id])->fetchAll(); ?>
<div class="support-thread-head"><b><?=security_html((string)$tik['title'])?></b><br>Автор: <a href="/user/<?=(int)$tik['user']?>/"><?=security_html((string)($tik['login']??('Игрок #'.$tik['user'])))?></a><br>Статус: <?=security_html(ticket_status((string)$tik['status']))?></div>
<div class="support-msg"><span class="support-date">Вопрос · <?=date('d.m.Y H:i',(int)$tik['time'])?></span><br><?=nl2br(security_html((string)$tik['text']))?></div>
<?php foreach($answers as $a): ?><div class="support-msg"><span class="support-date"><?=($a['type']==='admin'?'Администрация':'Игрок')?>:</span><br><?=nl2br(security_html((string)$a['text']))?></div><?php endforeach; ?>
<?php if($tik['status']!=='close'): ?><form method="post" action="/ticket/?mode=admin_view&id=<?=$id?>" class="support-form"><?=security_csrf_field()?><input type="hidden" name="action" value="admin_reply"><input type="hidden" name="ticket_id" value="<?=$id?>"><label>Ответ:<textarea name="body" rows="4" required></textarea></label><button class="support-submit" type="submit">Ответить</button></form>
<form method="post" action="/ticket/?mode=admin_view&id=<?=$id?>" class="inline-form"><?=security_csrf_field()?><input type="hidden" name="action" value="admin_close"><input type="hidden" name="ticket_id" value="<?=$id?>"><button class="link-button" type="submit">Закрыть обращение</button></form>
<?php else: ?><form method="post" action="/ticket/?mode=admin_view&id=<?=$id?>" class="inline-form"><?=security_csrf_field()?><input type="hidden" name="action" value="admin_reopen"><input type="hidden" name="ticket_id" value="<?=$id?>"><button class="link-button" type="submit">Открыть снова</button></form><?php endif; ?>
<a class="support-back" href="/adm/support/">› К обращениям</a>
<?php endif; ?>
<?php elseif($mode==='home'): ?>
<div class="support-title">Выберите тему:</div>
<a class="support-link" href="/ticket/?mode=create&type=general">Общие вопросы</a>
<a class="support-link" href="/ticket/?mode=create&type=sms">Вопросы об оплате с помощью SMS</a>
<a class="support-link" href="/ticket/?mode=create&type=payment">Вопросы об оплате прочими способами</a>
<?php $q=db_prepare('SELECT * FROM `ticket` WHERE `user`=:u ORDER BY `time` DESC,`id` DESC LIMIT 50',['u'=>(int)$user['id']]); $mine=$q->fetchAll(); if($mine): ?>
<div class="support-sep"></div><div class="support-title">Мои обращения</div>
<?php foreach($mine as $t): ?><a class="support-ticket-row" href="/ticket/?mode=view&id=<?=(int)$t['id']?>"><span class="support-doc">▤</span><?=security_html((string)$t['title'])?> <span class="support-date">(<?=date('d.m.y H:i',(int)$t['time'])?>)</span><?php if($t['status']==='read'): ?> <span class="green">(+)</span><?php endif; ?></a><?php endforeach; endif; ?>
<?php if($isStaff): ?><div class="support-sep"></div><a class="support-link" href="/adm/support/">Панель обращений администрации</a><?php endif; ?>
<?php elseif($mode==='create' && in_array($type,$allowed,true)): ?>
<form method="post" action="/ticket/?mode=create&type=<?=security_html($type)?>" class="support-form"><?=security_csrf_field()?><input type="text" name="website" class="hp-field" tabindex="-1" autocomplete="off"><input type="hidden" name="action" value="create"><div>Тема: <?=security_html(ticket_topic_label($type))?></div>
<?php if($type==='sms'): ?><label>Ваша страна:<input type="text" name="country"></label><label>Ваш оператор сотовой связи:<input type="text" name="operator"></label><label>Номер телефона:<input type="text" name="phone"></label><label>Короткий номер:<input type="text" name="short_number"></label><label>Дата и время отправления SMS:<input type="text" name="sent_at"></label><label>Текст отправленного SMS:<input type="text" name="sent_text"></label><label>Ответ SMS:<input type="text" name="reply_text"></label><?php endif; ?>
<label>Содержание:<textarea name="body" rows="4" required></textarea></label><button type="submit" class="support-submit">Создать</button></form>
<?php else:
$tik=$id>0?db_fetch_one('SELECT * FROM `ticket` WHERE `id`=:i AND `user`=:u LIMIT 1',['i'=>$id,'u'=>(int)$user['id']]):null;
if(!$tik): ?><div class="support-notice">Обращение не найдено.</div>
<?php else: $answers=db_prepare('SELECT * FROM `ticket_answer` WHERE `ticket`=:i ORDER BY `id` ASC',['i'=>(int)$tik['id']])->fetchAll();
if($tik['status']==='read') db_execute("UPDATE `ticket` SET `status`='new' WHERE `id`=:i",['i'=>(int)$tik['id']]); ?>
<div class="support-thread-head"><b><?=security_html((string)$tik['title'])?></b><br>Автор: <a href="/user/<?=(int)$user['id']?>/"><?=security_html((string)$user['login'])?></a><br>Статус: <?=security_html(ticket_status((string)$tik['status']))?></div>
<div class="support-msg"><span class="support-date">Вопрос: <?=date('d F H:i',(int)$tik['time'])?></span><br><?=nl2br(security_html((string)$tik['text']))?></div>
<?php foreach($answers as $a): ?><div class="support-msg"><span class="support-date"><?=($a['type']==='admin'?'Ответ администрации':'Я')?>:</span><br><?=nl2br(security_html((string)$a['text']))?></div><?php endforeach; ?>
<?php if($tik['status']!=='close'): ?><form method="post" action="/ticket/?mode=view&id=<?=(int)$tik['id']?>" class="support-form"><?=security_csrf_field()?><input type="hidden" name="action" value="reply"><label>Ответ:<textarea name="body" rows="3"></textarea></label><button class="support-submit" type="submit">Отправить</button></form><?php endif; ?>
<a class="support-back" href="/ticket/">› Вернуться назад</a>
<?php endif; endif; ?>
</div>
<?php require './system/f.php'; ?>