From 9e2bfd43193da029125f8621ca83cf1926a77e77 Mon Sep 17 00:00:00 2001 From: Pk11 Date: Wed, 1 Mar 2023 09:20:02 +0000 Subject: [PATCH] Initial commit --- .gitignore | 1 + LICENSE | 24 +++++ README.md | 19 ++++ assets/images/main-menu.png | Bin 0 -> 3272 bytes favicon.ico | Bin 0 -> 15086 bytes index.html | 37 ++++++++ share.php | 96 +++++++++++++++++++ vars.php.example | 7 ++ words.php | 180 ++++++++++++++++++++++++++++++++++++ 9 files changed, 364 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 assets/images/main-menu.png create mode 100644 favicon.ico create mode 100644 index.html create mode 100644 share.php create mode 100644 vars.php.example create mode 100644 words.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2dc8f9e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +vars.php diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..68a49da --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/README.md b/README.md new file mode 100644 index 0000000..9a1de0f --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# wordle.ピケ.コム + +## hosting +1. install: + - PHP (I use 8.2.1) + - PostgreSQL (I use 15.6) +2. clone this repo, `git clone https://git.xn--rck9c.xn--tckwe/pk11/wordle.git` +2. copy `vars.php.example` to `vars.php` +3. edit `vars.php` as explained in the file +4. create the following tables in the configured database: + ```sql + CREATE TABLE words ( + id INT PRIMARY KEY, + solution VARCHAR(5) NOT NULL, + print_date VARCHAR(10) NOT NULL, + days_since_launch INT, + editor VARCHAR(64) + ); + ``` diff --git a/assets/images/main-menu.png b/assets/images/main-menu.png new file mode 100644 index 0000000000000000000000000000000000000000..7c3aa2b46aa008cc77e5bf1bb0444a9757740c62 GIT binary patch literal 3272 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 S=oA0>xlVR2v@#od?Ee6dR(mG^ literal 0 HcmV?d00001 diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..217bcabe6bb0b66be4ea6b2507719bcb3557e939 GIT binary patch literal 15086 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 literal 0 HcmV?d00001 diff --git a/index.html b/index.html new file mode 100644 index 0000000..c2b8bf2 --- /dev/null +++ b/index.html @@ -0,0 +1,37 @@ + + + + + Wordle DS + + +

Wordle DS

+ The Wordle DS main menu +

About

+

+ A clone of Wordle for the Nintendo DS(i). It features everything from the official version including matching daily word plus some bonus features. +

+

Downloads

+ + +

API

+ http://wordle.xn--rck9c.xn--tckwe/words.php +

Variables:

+
+
date
+
[required] The oldest date to include in YYYY-MM-DD format. Must be 2021-06-19 or later.
+
limit
+
The maximum words to include. Default 100.
+
include
+
Columns to include, comma separated list. Default: id, solution, print_date, days_since_launch, editor. Additional: access_count. When only one column is included the json will be a flat array, no objects.
+
+ +

Share

+

Wordle DS can share to a web page for QR readers that cannot copy text directly.

+

Example message

+ + diff --git a/share.php b/share.php new file mode 100644 index 0000000..3e1a6f5 --- /dev/null +++ b/share.php @@ -0,0 +1,96 @@ + + */ + + // Return source code + if(isset($_GET['source'])) { + header("Content-Type: text/plain"); + die(file_get_contents(basename($_SERVER['PHP_SELF']))); + } + + $message = $_GET['message']; + $urlmessage = rawurlencode($message); + $subject = rawurlencode(strstr($message, "\n", TRUE)); + + $mobile = !!strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile'); + +?> + + + + + + Wordle DS URL Share + + +

Wordle DS URL Share

+ +

Error: No share message provided

+ +
+
+
+ [back] + [source] + [">email] + [">sms] + [">bbs] + [">reddit] + [">tumblr] + + + + + + + + +'; +$DB_USER = ''; +$DB_PASSWORD = ''; diff --git a/words.php b/words.php new file mode 100644 index 0000000..9db0d76 --- /dev/null +++ b/words.php @@ -0,0 +1,180 @@ + + */ + +// Return source code +if(isset($_GET['source'])) { + header("Content-Type: text/plain"); + die(file_get_contents(basename($_SERVER['PHP_SELF']))); +} + +header("Content-Type: application/json"); + +/* vars.php should contain the following, but with your variables as needed: + * + * // Database constants for PostgreSQL database + * $DB_HOST = 'localhost'; + * $DB_NAME = ''; + * $DB_USER = ''; + * $DB_PASSWORD = ''; + * + * You also need to run the following SQL: + * + * CREATE TABLE words ( + * id INT PRIMARY KEY, + * solution VARCHAR(5) NOT NULL, + * print_date VARCHAR(10) NOT NULL, + * days_since_launch INT, + * editor VARCHAR(64), + * access_count INT DEFAULT 0 + * ); + * + * CREATE TABLE update ( + * time TIMESTAMPTZ NOT NULL DEFAULT NOW(), + * lock BOOL PRIMARY KEY DEFAULT TRUE, + * CONSTRAINT lock_unique CHECK(lock) + * ); + * + * INSERT INTO update VALUES (NOW()); + */ +require_once('vars.php'); + +//// Functions: //// + +function get_words($date, $limit, $include) { + $query = "SELECT $include FROM words WHERE print_date>=$1 ORDER BY print_date ASC LIMIT $2"; + $res = pg_query_params($query, [$date, $limit]) or die('Query failed: ' . pg_last_error()); + + if(pg_num_rows($res) == 0) { + return [ + 'status' => 'ERROR', + 'message' => 'Date too late' + ]; + } + + while($row = pg_fetch_array($res, null, PGSQL_ASSOC)) { + $toint = ['id', 'days_since_launch', 'access_count']; + foreach($toint as $key) { + if(array_key_exists($key, $row)) + $row[$key] = intval($row[$key]); + } + $words[] = $row; + } + + $query = 'UPDATE words SET access_count=access_count+1 WHERE print_date>=$1'; + pg_query_params($query, [$date]) or die('Query failed ' . pg_last_error()); + + // If just one column, do a straight array + if(!str_contains($include, ',')) + $words = array_column($words, $include); + + return $words; +} + +function add_words($datestamp) { + $ret = false; + while(true) { + $date = date('Y-m-d', $datestamp); + $query = 'SELECT FROM words WHERE print_date=$1'; + $res = pg_query_params($query, [$date]) or die('Query failed: ' . pg_last_error()); + if(pg_num_rows($res) == 0) { + $content = file_get_contents("https://www.nytimes.com/svc/wordle/v2/$date.json"); + if(!$content) + break; + + $word = json_decode($content, true); + + // Add word to database + $query = 'INSERT INTO words (id, solution, print_date, days_since_launch, editor) ' . + 'VALUES ($1, $2, $3, $4, $5)'; + $params = [ + $word['id'], + $word['solution'], + $word['print_date'], + $word['days_since_launch'], + $word['editor'] + ]; + pg_query_params($query, $params) or die('Query failed: ' . pg_last_error()); + + $ret = true; // (at least one) word added + } + + $datestamp += 60 * 60 * 24; + } + + return $ret; +} + +//// Code start: //// + +// Connect to the database +$dbc = pg_connect("host=$DB_HOST dbname=$DB_NAME user=$DB_USER password=$DB_PASSWORD") + or die('Could not connect: ' . pg_last_error()); + +// Check get vars +$date = $_GET['date']; +$limit = isset($_GET['limit']) ? intval($_GET['limit']) : 100; +$include = isset($_GET['include']) ? $_GET['include'] : 'id,solution,print_date,days_since_launch,editor'; + +if(!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) { + die(json_encode([ + 'status' => 'ERROR', + 'message' => 'Invalid date format (YYYY-MM-DD)' + ])); +} else if($date < '2021-06-19') { + die(json_encode([ + 'status' => 'ERROR', + 'message' => 'Date too early' + ])); +} else if($limit <= 0) { + die(json_encode([ + 'status' => 'ERROR', + 'message' => 'Invalid limit' + ])); +} else if(!preg_match('/^[a-z,_]+$/', $include)) { + die(json_encode([ + 'status' => 'ERROR', + 'message' => 'Invalid include' + ])); +} + + +// Check for words once a day +$res = pg_query('SELECT EXTRACT(EPOCH FROM time) AS time FROM update') or die('Query failed: ' . pg_last_error()); +$cur_time = time(); +$last_time = pg_fetch_array($res)['time']; +if($cur_time > $last_time + (60 * 60 * 24)) { + add_words($cur_time); + + $query = 'UPDATE update SET time=TO_TIMESTAMP($1)'; + pg_query_params($query, [$cur_time]) or die('Query failed: ' . pg_last_error()); +} + +// Get words +echo json_encode(get_words($date, $limit, $include)); + +pg_close($dbc);