mirror of
https://github.com/ChronosX88/Influence-cjdns.git
synced 2024-11-08 17:01:00 +00:00
пример реализации мессенджера на PHP
This commit is contained in:
parent
856e8e42b0
commit
eadc19a6d8
2
php/.gitignore
vendored
Normal file
2
php/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
db
|
||||
server.conf
|
4
php/config.php
Normal file
4
php/config.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
|
||||
define('TIME_PING', 60); // пинг - раз в минуту
|
||||
define('TIME_ONLINE', 5*60); // через сколько секунд считать, что ушёл в offline
|
5
php/index.php
Normal file
5
php/index.php
Normal file
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
require_once 'init.php';
|
||||
|
||||
require_once 'tpl/index.tpl';
|
10
php/init.php
Normal file
10
php/init.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
require_once 'config.php';
|
||||
|
||||
require_once 'm/db.php';
|
||||
require_once 'm/api.php';
|
||||
require_once 'm/send.php';
|
||||
require_once 'm/functions.php';
|
||||
|
||||
require_once 'post.php';
|
23
php/m/api.php
Normal file
23
php/m/api.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
function api_get($uri, $handler)
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'GET')
|
||||
api_call($uri, $handler);
|
||||
}
|
||||
|
||||
function api_post($uri, $handler)
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST')
|
||||
api_call($uri, $handler);
|
||||
}
|
||||
|
||||
function api_call($uri, $handler)
|
||||
{
|
||||
if (preg_match("#^$uri$#", $_SERVER['REQUEST_URI'], $m))
|
||||
{
|
||||
foreach ($m as $k => $v) if (is_string($v)) $m[$k] = urldecode($v);
|
||||
if (is_callable($handler)) $handler($m);
|
||||
else require_once "tpl/$handler";
|
||||
}
|
||||
}
|
63
php/m/db.php
Normal file
63
php/m/db.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
function db_insert($db, $a)
|
||||
{
|
||||
$data = db_get($db);
|
||||
$data[] = $a;
|
||||
db_save($db, $data);
|
||||
}
|
||||
|
||||
function db_update($db, $a, $filter)
|
||||
{
|
||||
$data = db_get($db);
|
||||
foreach (db_search($db, $filter) as $id => $_)
|
||||
$data[$id] = $a + $data[$id];
|
||||
db_save($db, $data);
|
||||
}
|
||||
|
||||
function db_delete($db, $filter)
|
||||
{
|
||||
$data = db_get($db);
|
||||
foreach (db_search($db, $filter) as $id => $_)
|
||||
unset($data[$id]);
|
||||
db_save($db, $data);
|
||||
}
|
||||
|
||||
function db_search($db, $filter = [])
|
||||
{
|
||||
$res = [];
|
||||
foreach (db_get($db) as $id => $a)
|
||||
{
|
||||
foreach ($filter as $k => $v)
|
||||
if ($a[$k] != $v) continue 2;
|
||||
$res[$id] = $a;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
function db_search_one($db, $filter)
|
||||
{
|
||||
$res = db_search($db, $filter);
|
||||
foreach ($res as $a) return $a;
|
||||
return [];
|
||||
}
|
||||
|
||||
function db_get($db)
|
||||
{
|
||||
$fname = "./db/$db.json";
|
||||
if (!file_exists($fname)) return [];
|
||||
$db = @json_decode(@file_get_contents($fname), true);
|
||||
return $db ?: [];
|
||||
}
|
||||
|
||||
function db_save($db, $data)
|
||||
{
|
||||
$fname = "./db/$db.json";
|
||||
if (empty($data)) unlink($fname);
|
||||
else
|
||||
{
|
||||
$st = json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||
if (!file_exists($x = dirname($fname))) mkdir($x, 0777, true);
|
||||
if ($st) file_put_contents($fname, $st);
|
||||
}
|
||||
}
|
13
php/m/functions.php
Normal file
13
php/m/functions.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
function request($x)
|
||||
{
|
||||
return array_intersect_key($_REQUEST, array_fill_keys(explode(',', $x), 1));
|
||||
}
|
||||
|
||||
function redirect($x = NULL)
|
||||
{
|
||||
if (is_null($x)) $x = $_SERVER['REQUEST_URI'];
|
||||
header('Location: '.$x);
|
||||
exit;
|
||||
}
|
14
php/m/send.php
Normal file
14
php/m/send.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
function send($data)
|
||||
{
|
||||
$data_url = http_build_query ($data);
|
||||
$data_len = strlen ($data_url);
|
||||
|
||||
$context = stream_context_create([
|
||||
'http' => ['method'=>'POST','header'=>"Connection: close\r\nContent-Length: $data_len\r\n", 'content'=>$data_url]
|
||||
]);
|
||||
|
||||
$res = json_decode(@file_get_contents('http://'.$data['to'].'/messages/', false, $context), true);
|
||||
return !empty($res);
|
||||
}
|
80
php/post.php
Normal file
80
php/post.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
api_get('/ping', function(){
|
||||
$a = ['timestamp'=>time(), 'addr'=>$_SERVER['HTTP_HOST']];
|
||||
echo json_encode($a);
|
||||
exit;
|
||||
});
|
||||
|
||||
api_get('/contacts/ping', function(){
|
||||
foreach (db_search('contacts') as $a)
|
||||
if ($a['addr'] != $_SERVER['HTTP_HOST']) // COMMENT: сами себе не отправляем
|
||||
{
|
||||
if (time() - @$a['time_ping'] > TIME_PING)
|
||||
{
|
||||
$st = @file_get_contents('http://'.$a['addr'].'/ping');
|
||||
$json = json_decode($st, true);
|
||||
$x = $json ? ['time_online' => time()] : [];
|
||||
db_update('contacts', ['time_ping' => time()] + $x, ['addr'=>$a['addr']]);
|
||||
}
|
||||
// если на связи - пытаемся дотправить сообщения
|
||||
if (time() - $a['time_online'] < TIME_ONLINE)
|
||||
{
|
||||
$addr = $a['addr'];
|
||||
foreach (db_search("undelivered/$addr") as $a)
|
||||
if (send($a))
|
||||
{
|
||||
db_insert("messages/$addr", $a + ['received'=>time()]);
|
||||
db_delete("undelivered/$addr", ['timestamp'=>$a['timestamp']]);
|
||||
} else break;
|
||||
}
|
||||
if (!empty($data)) $a['messages'] = $data;
|
||||
}
|
||||
exit;
|
||||
});
|
||||
|
||||
api_get('/messages/(?<addr>[^/]+)', 'messages.tpl');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] != 'POST') return;
|
||||
|
||||
api_post('/contacts/(?<addr>[^/]+)', function($m){
|
||||
if (empty($_REQUEST['addr'])) die('Не указан адрес!');
|
||||
$addr = $m['addr'];
|
||||
$x = db_search('contacts', $addr == 'new' ? request('addr') : ['addr'=>$addr]);
|
||||
if ($addr == 'new')
|
||||
{
|
||||
if (!empty($x)) die('Такой адрес уже есть в базе!');
|
||||
db_insert('contacts', request('addr,nickname,email'));
|
||||
redirect('/contacts/');
|
||||
} else {
|
||||
if (request('delete'))
|
||||
{
|
||||
db_delete('contacts', ['addr'=>$addr]);
|
||||
redirect('/contacts/');
|
||||
}
|
||||
else
|
||||
db_update('contacts', request('addr,nickname,email'), ['addr'=>$addr]);
|
||||
}
|
||||
});
|
||||
|
||||
api_post('/messages/(?<addr>[^/]+)', function($m){
|
||||
$a = request('text') + ['from'=>$_SERVER['HTTP_HOST'], 'to'=>$m['addr'], 'timestamp'=>time()];
|
||||
if (send($a))
|
||||
db_insert('messages/'.$m['addr'], $a + ['received'=>time()]);
|
||||
else
|
||||
db_insert('undelivered/'.$m['addr'], $a);
|
||||
redirect($_SERVER['HTTP_REFERER']);
|
||||
});
|
||||
|
||||
api_post('/messages/', function($m){
|
||||
$a = request('from,to,text,timestamp');
|
||||
if ($a['to'] == $_SERVER['HTTP_HOST'])
|
||||
{
|
||||
db_insert('messages/'.$a['from'], $a + ['received'=>time()]);
|
||||
$res = ['received'=>time()];
|
||||
echo json_encode($res);
|
||||
}
|
||||
exit;
|
||||
});
|
||||
|
||||
redirect();
|
1
php/server.conf.example
Normal file
1
php/server.conf.example
Normal file
@ -0,0 +1 @@
|
||||
IP=127.0.0.1
|
4
php/server.sh
Executable file
4
php/server.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
source ./server.conf
|
||||
php -S $IP:8000 index.php
|
10
php/tpl/chat.tpl
Normal file
10
php/tpl/chat.tpl
Normal file
@ -0,0 +1,10 @@
|
||||
<h3>Сообщения</h3>
|
||||
|
||||
<iframe src="/messages/<?=$m['addr']?>" style="width: 600px; height: 400px;"></iframe>
|
||||
|
||||
<form method="POST" action="/messages/<?=$m['addr']?>">
|
||||
<input name="text" style="width: 300px">
|
||||
<input type="submit" value="Отправить">
|
||||
</form>
|
||||
|
||||
<script>setInterval(function(){ document.querySelector('iframe').contentWindow.location.reload(true) }, 10000)</script>
|
20
php/tpl/contact.tpl
Normal file
20
php/tpl/contact.tpl
Normal file
@ -0,0 +1,20 @@
|
||||
<?
|
||||
if ($m['addr'] == 'new')
|
||||
$action_name = 'Добавить';
|
||||
else
|
||||
{
|
||||
$action_name = 'Изменить';
|
||||
$a = db_search_one('contacts', ['addr'=>$m['addr']]);
|
||||
}
|
||||
?>
|
||||
<style>
|
||||
form { white-space: pre; font-family: Courier New; }
|
||||
</style>
|
||||
|
||||
<h2><?=$action_name?> контакт</h2>
|
||||
<form action="./<?=$m['addr']?>" method="POST">
|
||||
Адрес: <input name="<?=$x='addr'?>" value="<?=@$a[$x]?>" required>
|
||||
Ник: <input name="<?=$x='nickname'?>" value="<?=@$a[$x]?>">
|
||||
email: <input name="<?=$x='email'?>" value="<?=@$a[$x]?>" type="email">
|
||||
<input type="submit" value="<?=$action_name?>"> <?if ($m['addr'!='new']){?><input type="submit" name="delete" value="Удалить"><?}?>
|
||||
</form>
|
29
php/tpl/contacts.tpl
Normal file
29
php/tpl/contacts.tpl
Normal file
@ -0,0 +1,29 @@
|
||||
<h3>Контакты</h3>
|
||||
|
||||
<style>
|
||||
table { border-collapse: collapse; }
|
||||
td, th { border: 1px solid #999; padding: 5px 10px; }
|
||||
th { background: #EEE; }
|
||||
tr:hover { background: #EEE; }
|
||||
</style>
|
||||
|
||||
<a href="new">Добавить</a>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Адрес</th>
|
||||
<th>Ник</th>
|
||||
<th>email</th>
|
||||
<th>online</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<?foreach (db_search('contacts', []) as $a){?>
|
||||
<tr>
|
||||
<td><a href="<?=urlencode($a['addr'])?>"><?=$a['addr']?></a></td>
|
||||
<td><?=$a['nickname']?></td>
|
||||
<td><?=$a['email']?></td>
|
||||
<td><?=(time() - @$a['time_online'] > TIME_ONLINE)?'нет':'да'?></td>
|
||||
<td><a href="./<?=$a['addr']?>/messages">сообщения</a></td>
|
||||
</tr>
|
||||
<?}?>
|
||||
</table>
|
16
php/tpl/dns.tpl
Normal file
16
php/tpl/dns.tpl
Normal file
@ -0,0 +1,16 @@
|
||||
<h3>DNS записи</h3>
|
||||
|
||||
<a href="new">Добавить</a>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Адрес</th>
|
||||
<th>Домен</th>
|
||||
</tr>
|
||||
<?foreach (db_search('dns', []) as $a){?>
|
||||
<tr>
|
||||
<td><a href="<?=urlencode($a['addr'])?>"><?=$a['addr']?></a></td>
|
||||
<td><?=$a['domain']?></td>
|
||||
</tr>
|
||||
<?}?>
|
||||
</table>
|
19
php/tpl/dns_edit.tpl
Normal file
19
php/tpl/dns_edit.tpl
Normal file
@ -0,0 +1,19 @@
|
||||
<?
|
||||
if ($m['addr'] == 'new')
|
||||
$action_name = 'Добавить';
|
||||
else
|
||||
{
|
||||
$action_name = 'Изменить';
|
||||
$a = db_search_one('dns', ['addr'=>$m['addr']]);
|
||||
}
|
||||
?>
|
||||
<style>
|
||||
form { white-space: pre; font-family: Courier New; }
|
||||
</style>
|
||||
|
||||
<h2><?=$action_name?> запись</h2>
|
||||
<form action="./<?=$m['addr']?>" method="POST">
|
||||
Адрес: <input name="<?=$x='addr'?>" value="<?=@$a[$x]?>" required>
|
||||
Домен: <input name="<?=$x='domain'?>" value="<?=@$a[$x]?>" required>
|
||||
<input type="submit" value="<?=$action_name?>"> <?if ($m['addr'!='new']){?><input type="submit" name="delete" value="Удалить"><?}?>
|
||||
</form>
|
21
php/tpl/index.tpl
Normal file
21
php/tpl/index.tpl
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<p>Ваш IP: <?=$_SERVER['HTTP_HOST']?></p>
|
||||
|
||||
<nav>
|
||||
<a href="/contacts/">Контакты</a>
|
||||
</nav>
|
||||
<?
|
||||
api_get('/contacts/', 'contacts.tpl');
|
||||
api_get('/contacts/(?<addr>[^/]+)', 'contact.tpl');
|
||||
api_get('/contacts/(?<addr>[^/]+)/messages', 'chat.tpl');
|
||||
?>
|
||||
|
||||
<iframe id="ping" style="display: none"></iframe>
|
||||
<script>setInterval(function(){ document.querySelector('#ping').src = '/contacts/ping'; }, 5000)</script>
|
||||
</body>
|
||||
</html>
|
18
php/tpl/messages.tpl
Normal file
18
php/tpl/messages.tpl
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
$contacts = [];
|
||||
foreach (db_search('contacts') as $a) $contacts[$a['addr']] = $a['nickname'];
|
||||
$contacts[$_SERVER['HTTP_HOST']] = 'Я';
|
||||
?>
|
||||
|
||||
<?$a = array_merge(db_search('messages/'.$m['addr']), db_search('undelivered/'.$m['addr']));?>
|
||||
<?if (empty($a)) {?>
|
||||
<p>Список сообщений пуст</p>
|
||||
<?} else
|
||||
|
||||
foreach ($a as $a){?>
|
||||
<?=date('H:i:s', $a['timestamp'])?> <b><?=$contacts[$a['from']]?></b>: <?=$a['text']?>
|
||||
<?if (empty($a['received'])) echo ' <small><i>(не доставлено)</i></small>';?>
|
||||
<br>
|
||||
<?}?>
|
||||
|
||||
<?exit;?>
|
Loading…
Reference in New Issue
Block a user