You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

197 lines
5.9 KiB

<?php
/* 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 <http://unlicense.org/>
*/
// 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 name>';
* $DB_USER = '<db role name>';
* $DB_PASSWORD = '<db role 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' => 'Already up to date'
];
}
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);
// The Times' IDs for guess list answers don't seem to have any
// relation to the sorted list, so we're doing our own which is:
// The index in the guess list array, but 1 indexed and negative
require_once('word_lists.php');
if($word['id'] > count(CHOICES)) {
$word['id'] = -(array_search(strtoupper($word['solution']), GUESSES) + 1);
}
// Add word to database
$query = 'INSERT INTO words (id, solution, print_date, days_since_launch, editor) ' .
'VALUES ($1, UPPER($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 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
if($_GET['mode'] == 'mod.json') {
header('Content-Disposition: attachment; filename="mod.json"');
echo json_encode([
'words' => [
'order' => get_words('2021-06-19', 100000, 'id')
]
]);
} else {
// 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'
]));
}
echo json_encode(get_words($date, $limit, $include));
}
pg_close($dbc);