From ea95c63e1823437b97a7376d61ed1218900c5afa Mon Sep 17 00:00:00 2001 From: Gregory Trolliet Date: Wed, 25 Nov 2020 19:43:40 +0100 Subject: [PATCH 1/8] Add database type option --- README.md | 4 ++++ db.php | 4 +--- dbconfig_empty.php | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 38f676d..a76c7db 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ # SimpleWordsCloud This site allows to create simple words cloud, without any registrations. 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. diff --git a/db.php b/db.php index 76489e9..d09a175 100644 --- a/db.php +++ b/db.php @@ -22,9 +22,7 @@ class DataBase public function init() { require_once 'dbconfig.php'; - $dsn = 'pgsql:dbname=' . $dbname - . ';host=' . $host - . ';port=' . $port; + $dsn = "$type:dbname=$dbname;host=$host;port=$port"; try { $this->db = new PDO($dsn, $username, $password); $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); diff --git a/dbconfig_empty.php b/dbconfig_empty.php index 9a4c838..d8a342e 100644 --- a/dbconfig_empty.php +++ b/dbconfig_empty.php @@ -1,5 +1,5 @@ Date: Wed, 25 Nov 2020 19:52:13 +0100 Subject: [PATCH 2/8] Move the word comparison function to common file --- common.php | 16 ++++++++++++++++ db.php | 17 ++--------------- 2 files changed, 18 insertions(+), 15 deletions(-) create mode 100644 common.php diff --git a/common.php b/common.php new file mode 100644 index 0000000..177e45f --- /dev/null +++ b/common.php @@ -0,0 +1,16 @@ += 90 || $meta_perc >= 90 || $sndx_perc >= 90) { + return true; + } + if ($word_perc >= 80 && $meta_perc >= 80 && $sndx_perc >= 80) { + return true; + } + return false; +} diff --git a/db.php b/db.php index d09a175..fdfe2f9 100644 --- a/db.php +++ b/db.php @@ -1,5 +1,6 @@ bindValue(':cid', $cloudId, PDO::PARAM_INT); $stmt->execute(); while($data = $stmt->fetch()) { - if ($this->areWordsSimilar($data['word'], $word)) { + if (areWordsSimilar($data['word'], $word)) { $word = $data['word']; $wordId = $data['id_word']; break; @@ -276,18 +277,4 @@ class DataBase } 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; - } } From fea36cb86748e0a014bb3bad5845a934acffea2e Mon Sep 17 00:00:00 2001 From: Gregory Trolliet Date: Wed, 25 Nov 2020 22:13:59 +0100 Subject: [PATCH 3/8] Add load and local save of the cloud --- db.php | 115 ++++++++++++++++++++++++++++++++++++++--------- lang/lang_fr.ini | 2 + save.php | 38 +++++++++------- 3 files changed, 118 insertions(+), 37 deletions(-) diff --git a/db.php b/db.php index fdfe2f9..310b409 100644 --- a/db.php +++ b/db.php @@ -14,12 +14,17 @@ class DataBase const DEFAULT_SIZE = 3; private $db; + private $cloud; public function __construct() { $this->init(); } - + /** + * Initialize the database + * + * Store the PDO object in $db private class variable + */ public function init() { require_once 'dbconfig.php'; @@ -30,15 +35,19 @@ class DataBase $this->db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); } catch (PDOException $e) { echo $e->getMessage(); - return null; } } - + /** + * Check if the database is initialized or not + * @return boolean True if db is inizialized + */ public function isInit() { return isset($this->db); } - + /** + * Build the database tables, only if not existing + */ public function buildTables() { $stmt = $this->db->prepare(" @@ -65,31 +74,35 @@ class DataBase "); $stmt->execute(); } - - public function addWord(string $cloud, string $word) + /** + * Add a word to a cloud + * + * 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)) { return false; } - $stmt = $this->db->prepare(" - SELECT * - FROM clouds - WHERE code = :id; - "); - $stmt->bindValue(':id', $cloud, PDO::PARAM_STR); - $stmt->execute(); - $cloudId = null; - if ($data = $stmt->fetch()) { - $cloudId = $data['id_cloud']; - } else { + if (isset($cloud)) { + if (!$this->loadCloud($cloud)) { + return false; + } + } + if (!$this->isCloudSet()) { return false; } + $stmt = $this->db->prepare(" SELECT * FROM words WHERE cloud_id = :cid; "); - $stmt->bindValue(':cid', $cloudId, PDO::PARAM_INT); + $stmt->bindValue(':cid', $this->cloud['id'], PDO::PARAM_INT); $stmt->execute(); while($data = $stmt->fetch()) { if (areWordsSimilar($data['word'], $word)) { @@ -112,7 +125,7 @@ class DataBase VALUES (:w, :cid); "); $stmt->bindValue(':w', $word, PDO::PARAM_STR); - $stmt->bindValue(':cid', $cloudId, PDO::PARAM_INT); + $stmt->bindValue(':cid', $this->cloud['id'], PDO::PARAM_INT); $stmt->execute(); } } @@ -204,7 +217,69 @@ class DataBase } return true; } - + public function loadCloud($ref) + { + if (is_int($ref)) { + return $this->loadCloudById($ref); + } elseif (is_string($ref)) { + return $this->loadCloudByCode($ref); + } + } + 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['test'], + ); + return true; + } + $this->cloud = null; + return false; + } + 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['test'], + ); + 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) { $stmt = $this->db->prepare(" diff --git a/lang/lang_fr.ini b/lang/lang_fr.ini index d29e24e..b41be26 100644 --- a/lang/lang_fr.ini +++ b/lang/lang_fr.ini @@ -42,6 +42,8 @@ message = "Vous pouvez entrer ici un ou plusieurs mots, les mots vides ne seront submit = "Enregistrer" word = "Mot %d" 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 %s n'a pas été trouvé, veuillez vérifier votre lien." [duration] day = "un jour" diff --git a/save.php b/save.php index 00a8818..5a25fff 100644 --- a/save.php +++ b/save.php @@ -7,24 +7,28 @@ if (empty($_POST)) { } include 'templates/header.php'; -$id = null; -$cpt = 0; -$already_used = array(); -foreach ($_POST as $name => $value) { - $cpt; - if ($name == 'fid') { - $id = $value; - continue; - } - if (isset($id) && !in_array($value, $already_used)) { - $already_used[] = $value; - $value = trim(strtolower($value)); - $db->addWord($id, $value); - } - if ($cpt > 9) { - break; +if (!isset($_POST['fid'])) { + echo sprintf('

%s

', L::save_missingId); +} elseif (!$db->loadCloud($_POST['fid'])) { + echo sprintf('

%s

', L::save_cloudNotFound($_POST['fid'])); +} else { + $cpt = 0; + $already_used = array(); + foreach ($_POST as $name => $value) { + if ($name == 'fid') { + continue; + } + $cpt++; + if (!in_array($value, $already_used)) { + $already_used[] = $value; + $value = trim(strtolower($value)); + $db->addWord($value); + } + if ($cpt > 9) { + break; + } } + echo sprintf('

%s

', L::save_success); } -echo sprintf('

%s

', L::save_success); include 'templates/footer.php'; From 3fbeb0694821075f2a17965f419729a2c2a9093e Mon Sep 17 00:00:00 2001 From: Gregory Trolliet Date: Wed, 25 Nov 2020 22:28:36 +0100 Subject: [PATCH 4/8] Save the cloud after the creation --- db.php | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/db.php b/db.php index 310b409..1644016 100644 --- a/db.php +++ b/db.php @@ -215,6 +215,13 @@ class DataBase } catch (PDOEXception $e) { return false; } + $this->cloud = array( + 'id' => $this->db->lastInsertId(), + 'code' => $ref, + 'size' => $size, + 'delete_t' => $duration, + 'text' => $text, + ); return true; } public function loadCloud($ref) @@ -225,6 +232,11 @@ class DataBase 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(" @@ -240,19 +252,24 @@ class DataBase 'code' => $data['code'], 'size' => $data['size'], 'delete_t' => $data['delete_t'], - 'text' => $data['test'], + '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; + WHERE code = :code; "); $stmt->bindValue(':code', $code, PDO::PARAM_STR); $stmt->execute(); @@ -262,7 +279,7 @@ class DataBase 'code' => $data['code'], 'size' => $data['size'], 'delete_t' => $data['delete_t'], - 'text' => $data['test'], + 'text' => $data['text'], ); return true; } From 06de0eb561d056be7f6808bc56afcb8da93b96d4 Mon Sep 17 00:00:00 2001 From: Gregory Trolliet Date: Wed, 25 Nov 2020 22:35:28 +0100 Subject: [PATCH 5/8] Fix the duration set error --- create.php | 3 +-- db.php | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/create.php b/create.php index b047125..eb09d2a 100644 --- a/create.php +++ b/create.php @@ -29,7 +29,6 @@ if (empty($_POST)) { db->prepare(" INSERT INTO clouds(code, text, size, delete_t) VALUES (:code, :text, :size, :duration); From e072182ed46adde2d42d4d86c899f2fa1f251358 Mon Sep 17 00:00:00 2001 From: Gregory Trolliet Date: Wed, 25 Nov 2020 22:49:54 +0100 Subject: [PATCH 6/8] Set the cloud code length as a DataBase constant --- create.php | 4 ++-- db.php | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/create.php b/create.php index eb09d2a..28f8b00 100644 --- a/create.php +++ b/create.php @@ -29,8 +29,7 @@ if (empty($_POST)) { createCloud($token, $text, $size, $duration) && $cpt < 10) { $token = bin2hex(random_bytes($length)); $cpt++; + // TODO what to do if no cloud created? } $viewUrl = 'result.php?id=' . $token; $viewName = 'https://' . $_SERVER['HTTP_HOST'] . '/' . $viewUrl; diff --git a/db.php b/db.php index 52ea468..12f72f7 100644 --- a/db.php +++ b/db.php @@ -12,6 +12,7 @@ class DataBase 'month' => '+1 month' ); const DEFAULT_SIZE = 3; + const CLOUD_CODE_LENGTH = 6; private $db; private $cloud; From 0980d0a82f8bb62e1d24bc006a055999a9aa4585 Mon Sep 17 00:00:00 2001 From: Gregory Trolliet Date: Wed, 25 Nov 2020 22:53:07 +0100 Subject: [PATCH 7/8] Remove unused methods --- db.php | 25 ------------------------- get.php | 8 ++++++-- 2 files changed, 6 insertions(+), 27 deletions(-) diff --git a/db.php b/db.php index 12f72f7..200e285 100644 --- a/db.php +++ b/db.php @@ -163,31 +163,6 @@ class DataBase return $words; } - public function getWordsPercentage(string $id) - { - $words = $this->getWordsList($id); - $total = 0; - foreach ($words as $word) { - $total += $word[1]; - } - foreach ($words as $key => $word) { - $words[$key] = array($word[0], $word[1] / $total); - } - - 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( string $ref, string $text = '', diff --git a/get.php b/get.php index 3faa068..d35a5ae 100644 --- a/get.php +++ b/get.php @@ -12,8 +12,12 @@ if (!isset($_GET['id'])) { } $id = $_GET['id']; -if ($words = $db->getWordsRelative($id)) { - echo json_encode($words); +if ($words = $db->getWordsList($id)) { + $wordsClean = []; + foreach ($words as $key => $word) { + $wordsClean[] = array($word['word'], $word['relative']); + } + echo json_encode($wordsClean); } else { echo json_encode('No id'); } From 3ff96924fbc7055ede6109bfc54b7ac2f85a5aca Mon Sep 17 00:00:00 2001 From: Gregory Trolliet Date: Wed, 25 Nov 2020 23:15:38 +0100 Subject: [PATCH 8/8] Move the cloud.code generation to the DataBase class --- create.php | 23 +++++++++++----------- db.php | 51 ++++++++++++++++++++++++++++++++++++++++-------- lang/lang_fr.ini | 3 +++ 3 files changed, 58 insertions(+), 19 deletions(-) diff --git a/create.php b/create.php index 28f8b00..f24f899 100644 --- a/create.php +++ b/create.php @@ -29,7 +29,7 @@ if (empty($_POST)) { createCloud($token, $text, $size, $duration) && $cpt < 10) { - $token = bin2hex(random_bytes($length)); - $cpt++; - // TODO what to do if no cloud created? - } - $viewUrl = 'result.php?id=' . $token; - $viewName = 'https://' . $_SERVER['HTTP_HOST'] . '/' . $viewUrl; - $voteUrl = 'index.php?id=' . $token; - $voteName = 'https://' . $_SERVER['HTTP_HOST'] . '/' . $voteUrl; + + if ($cloud = $db->createCloud($text, $size, $duration)) { + $viewUrl = 'result.php?id=' . $cloud['code']; + $viewName = 'https://' . $_SERVER['HTTP_HOST'] . '/' . $viewUrl; + $voteUrl = 'index.php?id=' . $cloud['code']; + $voteName = 'https://' . $_SERVER['HTTP_HOST'] . '/' . $voteUrl; ?>

@@ -73,5 +69,10 @@ if (empty($_POST)) { +

+ '+1 month' ); const DEFAULT_SIZE = 3; + const MAX_SIZE = 9; const CLOUD_CODE_LENGTH = 6; private $db; @@ -162,29 +163,63 @@ class DataBase array_multisort($values, SORT_DESC, $words); return $words; } - + /** + * Create a new cloud + * + * The function will try to generate a new code for the cloud, + * if it fails, the function will return false, otherwise the + * cloud local variable will save the new cloud. + * @param string $text Text associated to the cloud. + * @param int $size The number of words asked each time, + * must be between 1 and MAX_SIZE. + * @param string $duration Duration code, from OPTIONS_DURATION. + * @return False if error, the cloud if success + */ public function createCloud( - string $ref, string $text = '', - int $size = null, + int $size = null, string $duration = null) { if (!isset($size)) { $size = 3; + } elseif ($size < 1) { + $size = 1; + } elseif ($size > self::MAX_SIZE) { + $size = self::MAX_SIZE; } if (!isset($duration)) { $duration = self::DEFAULT_DURATION; } elseif (!key_exists($duration, self::OPTIONS_DURATION)) { $duration = self::DEFAULT_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(" INSERT INTO clouds(code, text, size, delete_t) VALUES (:code, :text, :size, :duration); "); - $stmt->bindValue(':code', $ref); - $stmt->bindValue(':text', $text); - $stmt->bindValue(':size', $size); + $stmt->bindValue(':code', $code, PDO::PARAM_STR); + $stmt->bindValue(':text', $text, PDO::PARAM_STR); + $stmt->bindValue(':size', $size, PDO::PARAM_INT); $stmt->bindValue(':duration', $duration, PDO::PARAM_STR); try { $stmt->execute(); @@ -193,12 +228,12 @@ class DataBase } $this->cloud = array( 'id' => $this->db->lastInsertId(), - 'code' => $ref, + 'code' => $code, 'size' => $size, 'delete_t' => $duration, 'text' => $text, ); - return true; + return $this->cloud; } public function loadCloud($ref) { diff --git a/lang/lang_fr.ini b/lang/lang_fr.ini index b41be26..fea109d 100644 --- a/lang/lang_fr.ini +++ b/lang/lang_fr.ini @@ -45,6 +45,9 @@ 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 %s 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] day = "un jour" week = "une semaine"