Compare commits
No commits in common. "3ff96924fbc7055ede6109bfc54b7ac2f85a5aca" and "97c75691ce13a2cf4625a4d168991eeff9187785" have entirely different histories.
3ff96924fb
...
97c75691ce
8 changed files with 105 additions and 226 deletions
|
@ -1,7 +1,3 @@
|
||||||
# SimpleWordsCloud
|
# SimpleWordsCloud
|
||||||
This site allows to create simple words cloud, without any registrations.
|
This site allows to create simple words cloud, without any registrations.
|
||||||
There is nothing stored on the server except the words.
|
There is nothing stored on the server except the words.
|
||||||
|
|
||||||
## Database
|
|
||||||
Database config option is set in the dbconfig.php file,
|
|
||||||
example is in dbconfig_empty.php.
|
|
||||||
|
|
16
common.php
16
common.php
|
@ -1,16 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
|
|
||||||
function areWordsSimilar(string $word1, string $word2)
|
|
||||||
{
|
|
||||||
$word_sim = similar_text($word1, $word2, $word_perc);
|
|
||||||
$meta_sim = similar_text(metaphone($word1), metaphone($word2), $meta_perc);
|
|
||||||
$sndx_sim = similar_text(soundex_fr($word1), soundex_fr($word2), $sndx_perc);
|
|
||||||
if ($word_perc >= 90 || $meta_perc >= 90 || $sndx_perc >= 90) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ($word_perc >= 80 && $meta_perc >= 80 && $sndx_perc >= 80) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
26
create.php
26
create.php
|
@ -29,7 +29,9 @@ if (empty($_POST)) {
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
} else {
|
} else {
|
||||||
/*$token = bin2hex(random_bytes(DataBase::CLOUD_CODE_LENGTH));*/
|
|
||||||
|
$length = 6;
|
||||||
|
$token = bin2hex(random_bytes($length));
|
||||||
if (isset($_POST['fsize']) && is_numeric($_POST['fsize'])) {
|
if (isset($_POST['fsize']) && is_numeric($_POST['fsize'])) {
|
||||||
$size = $_POST['fsize'];
|
$size = $_POST['fsize'];
|
||||||
} else {
|
} else {
|
||||||
|
@ -40,17 +42,20 @@ if (empty($_POST)) {
|
||||||
} else {
|
} else {
|
||||||
$text = '';
|
$text = '';
|
||||||
}
|
}
|
||||||
if (isset($_POST['fduration']) && key_exists($_POST['fduration'], DataBase::OPTIONS_DURATION)) {
|
if (isset($_POST['fduration']) && in_array($_POST['fduration'], DataBase::OPTIONS_DURATION)) {
|
||||||
$duration = $_POST['fduration'];
|
$duration = $_POST['fduration'];
|
||||||
} else {
|
} else {
|
||||||
$duration = DataBase::DEFAULT_DURATION;
|
$duration = DataBase::DEFAULT_DURATION;
|
||||||
}
|
}
|
||||||
|
$cpt = 0;
|
||||||
if ($cloud = $db->createCloud($text, $size, $duration)) {
|
while (!$db->createCloud($token, $text, $size, $duration) && $cpt < 10) {
|
||||||
$viewUrl = 'result.php?id=' . $cloud['code'];
|
$token = bin2hex(random_bytes($length));
|
||||||
$viewName = 'https://' . $_SERVER['HTTP_HOST'] . '/' . $viewUrl;
|
$cpt++;
|
||||||
$voteUrl = 'index.php?id=' . $cloud['code'];
|
}
|
||||||
$voteName = 'https://' . $_SERVER['HTTP_HOST'] . '/' . $voteUrl;
|
$viewUrl = 'result.php?id=' . $token;
|
||||||
|
$viewName = 'https://' . $_SERVER['HTTP_HOST'] . '/' . $viewUrl;
|
||||||
|
$voteUrl = 'index.php?id=' . $token;
|
||||||
|
$voteName = 'https://' . $_SERVER['HTTP_HOST'] . '/' . $voteUrl;
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<h2><?php echo L::cloud_links_warning ?></h2>
|
<h2><?php echo L::cloud_links_warning ?></h2>
|
||||||
|
@ -69,10 +74,5 @@ if (empty($_POST)) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
} else {
|
|
||||||
?>
|
|
||||||
<h2><?php echo L::create_errorCode ?></h2>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
include('templates/footer.php');
|
include('templates/footer.php');
|
||||||
|
|
232
db.php
232
db.php
|
@ -1,6 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
require_once 'soundex_fr.php';
|
require_once 'soundex_fr.php';
|
||||||
require_once 'common.php';
|
|
||||||
|
|
||||||
class DataBase
|
class DataBase
|
||||||
{
|
{
|
||||||
|
@ -12,44 +11,35 @@ class DataBase
|
||||||
'month' => '+1 month'
|
'month' => '+1 month'
|
||||||
);
|
);
|
||||||
const DEFAULT_SIZE = 3;
|
const DEFAULT_SIZE = 3;
|
||||||
const MAX_SIZE = 9;
|
|
||||||
const CLOUD_CODE_LENGTH = 6;
|
|
||||||
|
|
||||||
private $db;
|
private $db;
|
||||||
private $cloud;
|
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->init();
|
$this->init();
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Initialize the database
|
|
||||||
*
|
|
||||||
* Store the PDO object in $db private class variable
|
|
||||||
*/
|
|
||||||
public function init()
|
public function init()
|
||||||
{
|
{
|
||||||
require_once 'dbconfig.php';
|
require_once 'dbconfig.php';
|
||||||
$dsn = "$type:dbname=$dbname;host=$host;port=$port";
|
$dsn = 'pgsql:dbname=' . $dbname
|
||||||
|
. ';host=' . $host
|
||||||
|
. ';port=' . $port;
|
||||||
try {
|
try {
|
||||||
$this->db = new PDO($dsn, $username, $password);
|
$this->db = new PDO($dsn, $username, $password);
|
||||||
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
$this->db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
$this->db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
echo $e->getMessage();
|
echo $e->getMessage();
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Check if the database is initialized or not
|
|
||||||
* @return boolean True if db is inizialized
|
|
||||||
*/
|
|
||||||
public function isInit()
|
public function isInit()
|
||||||
{
|
{
|
||||||
return isset($this->db);
|
return isset($this->db);
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Build the database tables, only if not existing
|
|
||||||
*/
|
|
||||||
public function buildTables()
|
public function buildTables()
|
||||||
{
|
{
|
||||||
$stmt = $this->db->prepare("
|
$stmt = $this->db->prepare("
|
||||||
|
@ -76,38 +66,34 @@ class DataBase
|
||||||
");
|
");
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Add a word to a cloud
|
public function addWord(string $cloud, string $word)
|
||||||
*
|
|
||||||
* If the cloud is specified, it will be loaded and the word
|
|
||||||
* will be added.
|
|
||||||
* If the cloud isn't specified, the already loaded cloud will be used.
|
|
||||||
* @param string $word Word to add
|
|
||||||
* @param string|int $cloud Id or code of the cloud
|
|
||||||
*/
|
|
||||||
public function addWord(string $word, $cloud = null)
|
|
||||||
{
|
{
|
||||||
if (empty($word)) {
|
if (empty($word)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (isset($cloud)) {
|
$stmt = $this->db->prepare("
|
||||||
if (!$this->loadCloud($cloud)) {
|
SELECT *
|
||||||
return false;
|
FROM clouds
|
||||||
}
|
WHERE code = :id;
|
||||||
}
|
");
|
||||||
if (!$this->isCloudSet()) {
|
$stmt->bindValue(':id', $cloud, PDO::PARAM_STR);
|
||||||
|
$stmt->execute();
|
||||||
|
$cloudId = null;
|
||||||
|
if ($data = $stmt->fetch()) {
|
||||||
|
$cloudId = $data['id_cloud'];
|
||||||
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $this->db->prepare("
|
$stmt = $this->db->prepare("
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM words
|
FROM words
|
||||||
WHERE cloud_id = :cid;
|
WHERE cloud_id = :cid;
|
||||||
");
|
");
|
||||||
$stmt->bindValue(':cid', $this->cloud['id'], PDO::PARAM_INT);
|
$stmt->bindValue(':cid', $cloudId, PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
while($data = $stmt->fetch()) {
|
while($data = $stmt->fetch()) {
|
||||||
if (areWordsSimilar($data['word'], $word)) {
|
if ($this->areWordsSimilar($data['word'], $word)) {
|
||||||
$word = $data['word'];
|
$word = $data['word'];
|
||||||
$wordId = $data['id_word'];
|
$wordId = $data['id_word'];
|
||||||
break;
|
break;
|
||||||
|
@ -127,7 +113,7 @@ class DataBase
|
||||||
VALUES (:w, :cid);
|
VALUES (:w, :cid);
|
||||||
");
|
");
|
||||||
$stmt->bindValue(':w', $word, PDO::PARAM_STR);
|
$stmt->bindValue(':w', $word, PDO::PARAM_STR);
|
||||||
$stmt->bindValue(':cid', $this->cloud['id'], PDO::PARAM_INT);
|
$stmt->bindValue(':cid', $cloudId, PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,151 +149,63 @@ class DataBase
|
||||||
array_multisort($values, SORT_DESC, $words);
|
array_multisort($values, SORT_DESC, $words);
|
||||||
return $words;
|
return $words;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Create a new cloud
|
public function getWordsPercentage(string $id)
|
||||||
*
|
{
|
||||||
* The function will try to generate a new code for the cloud,
|
$words = $this->getWordsList($id);
|
||||||
* if it fails, the function will return false, otherwise the
|
$total = 0;
|
||||||
* cloud local variable will save the new cloud.
|
foreach ($words as $word) {
|
||||||
* @param string $text Text associated to the cloud.
|
$total += $word[1];
|
||||||
* @param int $size The number of words asked each time,
|
}
|
||||||
* must be between 1 and MAX_SIZE.
|
foreach ($words as $key => $word) {
|
||||||
* @param string $duration Duration code, from OPTIONS_DURATION.
|
$words[$key] = array($word[0], $word[1] / $total);
|
||||||
* @return False if error, the cloud if success
|
}
|
||||||
*/
|
|
||||||
|
return $words;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWordsRelative(string $id)
|
||||||
|
{
|
||||||
|
$words = $this->getWordsList($id);
|
||||||
|
$wordsClean = [];
|
||||||
|
foreach ($words as $key => $word) {
|
||||||
|
$wordsClean[] = array($word['word'], $word['relative']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $wordsClean;
|
||||||
|
}
|
||||||
|
|
||||||
public function createCloud(
|
public function createCloud(
|
||||||
|
string $ref,
|
||||||
string $text = '',
|
string $text = '',
|
||||||
int $size = null,
|
int $size = null,
|
||||||
string $duration = null)
|
string $duration = null)
|
||||||
{
|
{
|
||||||
if (!isset($size)) {
|
if (!isset($size)) {
|
||||||
$size = 3;
|
$size = 3;
|
||||||
} elseif ($size < 1) {
|
|
||||||
$size = 1;
|
|
||||||
} elseif ($size > self::MAX_SIZE) {
|
|
||||||
$size = self::MAX_SIZE;
|
|
||||||
}
|
}
|
||||||
if (!isset($duration)) {
|
if (!isset($duration)) {
|
||||||
$duration = self::DEFAULT_DURATION;
|
$duration = self::DEFAULT_DURATION;
|
||||||
} elseif (!key_exists($duration, self::OPTIONS_DURATION)) {
|
} elseif (!in_array($duration, self::OPTIONS_DURATION)) {
|
||||||
$duration = self::DEFAULT_DURATION;
|
$duration = self::DEFAULT_DURATION;
|
||||||
}
|
}
|
||||||
|
$duration = date('Y-m-d H:i:s', strtotime($duration));
|
||||||
$cpt = 0;
|
|
||||||
$codeIsUsed = true;
|
|
||||||
while ($codeIsUsed && $cpt < 0) {
|
|
||||||
$code = bin2hex(random_bytes(self::CLOUD_CODE_LENGTH));
|
|
||||||
$stmt = $this->db->prepare("
|
|
||||||
SELECT *
|
|
||||||
FROM clouds
|
|
||||||
WHERE code = :code;
|
|
||||||
");
|
|
||||||
$stmt->bindValue(':code', $code);
|
|
||||||
$stmt->execute();
|
|
||||||
if (!$data = $stmt->fetch()) {
|
|
||||||
$codeIsUsed = false;
|
|
||||||
}
|
|
||||||
$cpt++;
|
|
||||||
}
|
|
||||||
if ($codeIsUsed) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$duration = date('Y-m-d H:i:s', strtotime(self::OPTIONS_DURATION[$duration]));
|
|
||||||
$stmt = $this->db->prepare("
|
$stmt = $this->db->prepare("
|
||||||
INSERT INTO clouds(code, text, size, delete_t)
|
INSERT INTO clouds(code, text, size, delete_t)
|
||||||
VALUES (:code, :text, :size, :duration);
|
VALUES (:code, :text, :size, :duration);
|
||||||
");
|
");
|
||||||
$stmt->bindValue(':code', $code, PDO::PARAM_STR);
|
$stmt->bindValue(':code', $ref);
|
||||||
$stmt->bindValue(':text', $text, PDO::PARAM_STR);
|
$stmt->bindValue(':text', $text);
|
||||||
$stmt->bindValue(':size', $size, PDO::PARAM_INT);
|
$stmt->bindValue(':size', $size);
|
||||||
$stmt->bindValue(':duration', $duration, PDO::PARAM_STR);
|
$stmt->bindValue(':duration', $duration, PDO::PARAM_STR);
|
||||||
try {
|
try {
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
} catch (PDOEXception $e) {
|
} catch (PDOEXception $e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$this->cloud = array(
|
return true;
|
||||||
'id' => $this->db->lastInsertId(),
|
|
||||||
'code' => $code,
|
|
||||||
'size' => $size,
|
|
||||||
'delete_t' => $duration,
|
|
||||||
'text' => $text,
|
|
||||||
);
|
|
||||||
return $this->cloud;
|
|
||||||
}
|
|
||||||
public function loadCloud($ref)
|
|
||||||
{
|
|
||||||
if (is_int($ref)) {
|
|
||||||
return $this->loadCloudById($ref);
|
|
||||||
} elseif (is_string($ref)) {
|
|
||||||
return $this->loadCloudByCode($ref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Load the cloud by its id
|
|
||||||
* @param int $id code of the cloud
|
|
||||||
* @return boolean True if the loading is done, False otherwise
|
|
||||||
*/
|
|
||||||
public function loadCloudById(int $id)
|
|
||||||
{
|
|
||||||
$stmt = $this->db->prepare("
|
|
||||||
SELECT *
|
|
||||||
FROM clouds
|
|
||||||
WHERE id_cloud = :id;
|
|
||||||
");
|
|
||||||
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
|
|
||||||
$stmt->execute();
|
|
||||||
if ($data = $stmt->fetch()) {
|
|
||||||
$this->cloud = array(
|
|
||||||
'id' => $data['id_cloud'],
|
|
||||||
'code' => $data['code'],
|
|
||||||
'size' => $data['size'],
|
|
||||||
'delete_t' => $data['delete_t'],
|
|
||||||
'text' => $data['text'],
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
$this->cloud = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Load the cloud by its code
|
|
||||||
* @param string $code code of the cloud
|
|
||||||
* @return boolean True if the loading is done, False otherwise
|
|
||||||
*/
|
|
||||||
public function loadCloudByCode(string $code)
|
|
||||||
{
|
|
||||||
$stmt = $this->db->prepare("
|
|
||||||
SELECT *
|
|
||||||
FROM clouds
|
|
||||||
WHERE code = :code;
|
|
||||||
");
|
|
||||||
$stmt->bindValue(':code', $code, PDO::PARAM_STR);
|
|
||||||
$stmt->execute();
|
|
||||||
if ($data = $stmt->fetch()) {
|
|
||||||
$this->cloud = array(
|
|
||||||
'id' => $data['id_cloud'],
|
|
||||||
'code' => $data['code'],
|
|
||||||
'size' => $data['size'],
|
|
||||||
'delete_t' => $data['delete_t'],
|
|
||||||
'text' => $data['text'],
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
$this->cloud = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public function isCloudSet()
|
|
||||||
{
|
|
||||||
return isset($this->cloud);
|
|
||||||
}
|
|
||||||
public function getCloudId()
|
|
||||||
{
|
|
||||||
if ($this->isCloudSet()) {
|
|
||||||
return $this->cloud['id'];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCloudSize(string $ref)
|
public function getCloudSize(string $ref)
|
||||||
{
|
{
|
||||||
$stmt = $this->db->prepare("
|
$stmt = $this->db->prepare("
|
||||||
|
@ -380,4 +278,18 @@ class DataBase
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function areWordsSimilar(string $word1, string $word2)
|
||||||
|
{
|
||||||
|
$word_sim = similar_text($word1, $word2, $word_perc);
|
||||||
|
$meta_sim = similar_text(metaphone($word1), metaphone($word2), $meta_perc);
|
||||||
|
$sndx_sim = similar_text(soundex_fr($word1), soundex_fr($word2), $sndx_perc);
|
||||||
|
if ($word_perc >= 90 || $meta_perc >= 90 || $sndx_perc >= 90) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ($word_perc >= 80 && $meta_perc >= 80 && $sndx_perc >= 80) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
$type = 'pgsql';
|
|
||||||
$host = 'localhost';
|
$host = 'localhost';
|
||||||
$dbname = '';
|
$dbname = '';
|
||||||
$username = '';
|
$username = '';
|
||||||
|
|
8
get.php
8
get.php
|
@ -12,12 +12,8 @@ if (!isset($_GET['id'])) {
|
||||||
}
|
}
|
||||||
$id = $_GET['id'];
|
$id = $_GET['id'];
|
||||||
|
|
||||||
if ($words = $db->getWordsList($id)) {
|
if ($words = $db->getWordsRelative($id)) {
|
||||||
$wordsClean = [];
|
echo json_encode($words);
|
||||||
foreach ($words as $key => $word) {
|
|
||||||
$wordsClean[] = array($word['word'], $word['relative']);
|
|
||||||
}
|
|
||||||
echo json_encode($wordsClean);
|
|
||||||
} else {
|
} else {
|
||||||
echo json_encode('No id');
|
echo json_encode('No id');
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,11 +42,6 @@ message = "Vous pouvez entrer ici un ou plusieurs mots, les mots vides ne seront
|
||||||
submit = "Enregistrer"
|
submit = "Enregistrer"
|
||||||
word = "Mot %d"
|
word = "Mot %d"
|
||||||
success = "Vos mots ont bien été enregistrés, merci de votre participation."
|
success = "Vos mots ont bien été enregistrés, merci de votre participation."
|
||||||
missingId = "Le formulaire est mal formé, veuillez contacter la personne responsable du site."
|
|
||||||
cloudNotFound = "Le nuage <em>%s</em> n'a pas été trouvé, veuillez vérifier votre lien."
|
|
||||||
|
|
||||||
[create]
|
|
||||||
errorCode = "Erreur lors de la création du nuage, désolé du dérangement."
|
|
||||||
|
|
||||||
[duration]
|
[duration]
|
||||||
day = "un jour"
|
day = "un jour"
|
||||||
|
|
38
save.php
38
save.php
|
@ -7,28 +7,24 @@ if (empty($_POST)) {
|
||||||
}
|
}
|
||||||
include 'templates/header.php';
|
include 'templates/header.php';
|
||||||
|
|
||||||
if (!isset($_POST['fid'])) {
|
$id = null;
|
||||||
echo sprintf('<h3>%s</h3>', L::save_missingId);
|
$cpt = 0;
|
||||||
} elseif (!$db->loadCloud($_POST['fid'])) {
|
$already_used = array();
|
||||||
echo sprintf('<h3>%s</h3>', L::save_cloudNotFound($_POST['fid']));
|
foreach ($_POST as $name => $value) {
|
||||||
} else {
|
$cpt;
|
||||||
$cpt = 0;
|
if ($name == 'fid') {
|
||||||
$already_used = array();
|
$id = $value;
|
||||||
foreach ($_POST as $name => $value) {
|
continue;
|
||||||
if ($name == 'fid') {
|
}
|
||||||
continue;
|
if (isset($id) && !in_array($value, $already_used)) {
|
||||||
}
|
$already_used[] = $value;
|
||||||
$cpt++;
|
$value = trim(strtolower($value));
|
||||||
if (!in_array($value, $already_used)) {
|
$db->addWord($id, $value);
|
||||||
$already_used[] = $value;
|
}
|
||||||
$value = trim(strtolower($value));
|
if ($cpt > 9) {
|
||||||
$db->addWord($value);
|
break;
|
||||||
}
|
|
||||||
if ($cpt > 9) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
echo sprintf('<h3>%s</h3>', L::save_success);
|
|
||||||
}
|
}
|
||||||
|
echo sprintf('<h3>%s</h3>', L::save_success);
|
||||||
|
|
||||||
include 'templates/footer.php';
|
include 'templates/footer.php';
|
||||||
|
|
Loading…
Reference in a new issue