|
Home Pages Pidgin Azarennya (S|N) Mac Thesaurus Reference ToDo Colino Food Local Blogs: BadIdea Rachel RIAA Cult: Clambake Infidels Fi: Arda StarTrek Trek/Wars Film: IMDB D Harry Jabootu Kyle Fun: Agony ICanHas? ObSkills Snopes Lang: ZBB Vreleksá AwkWords Omniglot Scriptorium More... Local: Maps Map MyWeb Metro (map) FC Weather GoWhere? GGWash DC Arlington Reston Beyond Bacon Pix: Deviant Places Renderosity Blender Artists Pol: Anchoress Lizards Lucianne Strata WAwakes Sci: SmallThings Darwin AntiEvo Skeptics EvC BAUT Physics /.Sci Junk Panda Pharyngula Mags AmSci NatG Space X86: OSX86 ArsTech OSNews TUAW Dev PowWeb PHP Webmaster Coding Walkers Prog: PHP JS Toolbox Unobt Compress RegExp (test) Lint SQL Cocoa Builder Dev Apple BBS Userland Faqin Science/Tech: Engadget Thunderbolts Icecap Centauri NewSci Gizmodo co2sci ClimateDebate SciDaily Nrich NatGeog Math CreatClaims GoodBadMath CurrentEvents: OrigSig Flamingo FlopAces ImmigProf ~J~ MyVRWC NewsGroper Pal2Pal Sanity Simon TCS Toldjah Blogs... Tools: Calculator AsciiArt XMLVal FunStuff: Pictures: Photobucket (eg Dubai) Videos: YouTube Subtitler InterestingThings: LibraryThing FlashCards GoogleDocs Wowio Bubbl.us Colemak Audible PodioBooks WonderfulInfo BooksOnline AboutUs.org |
KE /
KEI might take up writing PHP again. I'd like the site to serve multiple articles per page, instead of one article per page which is what Wiki software does. KEKE is my next attempt at a web-snippet application. File Formats
CodeThe snip.php contains the heart of Snip. All of its functionality is available through just three functions:
[[http://karig.net/KE/KE?action=edit|(edit)]]
define ('SNIP_DIR', 'snipdata');
define ('OLD_SNIP_DIR', 'snipvers');
define ('KEY_INDEX_DIR', 'snipkeys');
define ('TEXT_INDEX_DIR', 'sniptext');
define ('LINES_PER_SNIP_FILE', 1024);
function save ($theKeys, $theText, $theID) {
foreach (array (SNIP_DIR, OLD_SNIP_DIR, KEY_INDEX_DIR, TEXT_INDEX_DIR) as $dir) {
if (!file_exists($dir)) mkdir ($dir, 0744);
}
// if (!isset($theID) or $theID isn't in the database) {
// $theID = new_id();
// }
list ($hid, $lid) = split_id ($theID);
// PRESERVE EXISTING SNIPPET AS PREVIOUS VERSION
$snips = file ("SNIP_DIR/$hid");
if ($snips[$lid] != '') {
if ($handle = fopen("OLD_SNIP_DIR/$hid/$lid", 'a')) {
fwrite ($handle, $snips[$lid]);
fclose ($handle);
}
}
$snips = array();
// SAVE NEW VERSION OF SNIPPET AS CURRENT VERSION
$theKeys = trim(preg_replace('/\s\s+/', ' ', $theKeys))
$k = sprintf('%d ', time()) . $theKeys;
$t = str_replace(array("\r","\n"), array(" "," "), $theText) . "\n";
overwrite_line ("SNIP_DIR/$hid", $k . chr(9) . $t, $lid);
// UPDATE KEYWORD INDEX
overwrite_line ("KEY_INDEX_DIR/$hid", $theKeys, $lid);
// UPDATE FULL-TEXT INDEX
overwrite_line ("TEXT_INDEX_DIR/$hid", fulltextify($lid . ' ' . $theText), $lid);
return $theID; // Needed when a new snippet is created!
}
function split_id ($theID) {
return array(
floor ($ID / LINES_PER_SNIP_FILE),
($ID % LINES_PER_SNIP_FILE)
);
}
function overwrite_line ($thePath, $theLine, $lineNumber) {
if ($lineNumber < 0) return false;
$lines = file($thePath);
$lines [$lineNumber] = $theLine;
if (!$handle = fopen($path, 'w')) return false;
fwrite ($handle, join ('', $lines));
fclose ($handle);
return true;
}
function fulltextify ($text) {
$text = strtolower(strip_tags($text));
$text = preg_replace('/\s\s+/', ' ', $text);
return $text;
}
class Snippet {
var $id;
var $date;
var $keywords;
var $text; //unlinefied
var $version;
function Snippet($theID, $theKeys, $theText) {
$id = isset($theID)? $theID : $this->new_id();
$keywords = isset($theKeys)? $theKeys : array();
$text = isset($theText)? $theText : '';
}
function Load($theID, $theVersion) {
if (!isset($theVersion)) {
// LOAD LINE FROM SNIPPET FILE
} else {
// LOAD LINE FROM VERSION FILE
}
// GET DATE, KEYWORDS AND TEXT FROM LINE
}
function new_id() {
// Look at server data for next snippet ID to use
// and return ID.
}
function linefy ($text) {
return str_replace(array("\r","\n"), array(" "," "), $text) . "\n";
}
function delinefy ($text) {
return str_replace(array(" "," "), array("\r","\n"), rtrim($text));
}
}
ActionsTop-level actions
Use classes?
Utilities
define ('LINES_PER_SNIP_FILE', 2048);
function debug_log($text) {append_file("debuglog.txt", $text);}
function snip_pack($keys, $text) {
return str_replace(chr(9), ' ', $keys) . chr(9) . linefy($text);
}
function overwrite_file($path, $data) {return do_write_file($path, $data, 'w');}
function append_file($path, $data) {return do_write_file($path, $data, 'a');}
function do_write_file($path, $data, $mode) {
if (!$handle = fopen ($path, $mode)) {return false;}
fwrite ($handle, $data);
fclose ($handle);
return true;
}
function snip_path ($ID) {return '/snip/' . idhigh($ID);}
function snip_line ($ID) {return idlow($ID);}
function version_path ($ID) {return '/vers/' . idhigh($ID) . '/' . idlow($ID);}
function idhigh ($ID) {return floor ($ID / LINES_PER_SNIP_FILE);}
function idlow ($ID) {return ($ID % LINES_PER_SNIP_FILE);}
function linefy ($text) {
return str_replace(array("\r","\n"), array(" "," "), $text) . "\n";
}
function delinefy ($text) {
return str_replace(array(" "," "), array("\r","\n"), rtrim($text));
}
Old(Reconsider)
PartsFile: .htaccessThis tells the server to serve "index.php" whenever a 404 (file not found) error occurs. (See also "The Perfect 404.") Script: index.phpThis serves up one or more snippets for reading. Each snippet has an "Edit" link, which invokes priv/edit.php on that snippet. The top of the screen displays a search box. search(int offset, int count, array words)The search function opens the "keys" file and jumps to the line specified in "offset". The search function searches for snippets and returns an array:
The function works by opening the "keys" file, offsetting to a specific line (set by "offset"), and reading in a number of lines (set by "count"). Each line contains the name of a snippet and the keywords associated with each snippet. Elements [0] and [1] are created using these. After this, the snippets' text files are opened Folder: s (snippets)Each snippet has a number, which is used to derive (1) the file in which the snippet is stored, and (2) the number of the line containing the snippet. LINES_PER_SNIPPET_FILE = 2048 filename = floor(snippet_ID / LINES_PER_SNIPPET_FILE) line_number = snippet_ID % LINES_PER_SNIPPET_FILE Whenever a snippet is saved, it is "linefied" -- All snippets are saved in files in the "s" folder. If each file is allowed up to 2048 lines ( Folder: v (versions)Whenever a snippet is edited, the previous version of the snippet is appended to a version file, which is stored in a subfolder of the "v" folder. The name of the version file is the same as the line_number above, which is the offset into a snippet file to the current version of the snippet. The name of the subfolder is the same as the snippet file name. Thus all non-current versions of a given snippet are stored together in a single file, and each subfolder contains versions of only those snippets whose current versions comprise the contents of a particular snippet file. Folder: t (texts)A snippet is saved twice -- once as HTML into the snippet file, and once as plain text into the full-text file, which is used for searches. Each snippet in the full-text file is saved as a snippet ID, a space, the "fulltextified" text (all lowercase, no punctuation, no whitespace except single spaces), and a newline. (The presence of the snippet ID simplifies searches: As soon as you find a phrase or keyword, search back for the newline and grab the numeric characters that follow.) Folder: k (keywords)Each snippet can have keywords associated with it. These are stored in a keyword file, whose structure mirrors that of the snippet file. Keywords are stored separately from text, because we're supposed to be able to assign keywords to snippets without including keywords in snippet text, and keywords are intended to be faster and to work like categories. Folder: privThis is a password-protected folder containing the edit.php and save.php scripts. Script: priv/edit.phpThis script takes a parameter "n" containing the number (ID) of the snippet to edit. If this is not given, then edit.php displays a blank screen so you can create a new snippet. This script displays three fields: snippet ID, keyword list, and snippet text. You can:
Script: priv/save.phpThis script takes a parameter "back", indicating how many steps back Javascript should take through the browser history. The default is 1, so that once the save is completed, you are returned to the editor. Script: priv/restore.phpThis script takes a parameter "n" containing the ID of the snippet. If this is not given, the script displays a list of snippets and asks you to pick one and click "See versions". This script lets you restore a previous version of a snippet. It displays previous versions of a given snippet, so that you can delete one or more of them, or select one for editing. (Once edit.php is running, you click "Save" to restore the text as the new current version of the snippet.) Code overviewMost code should go into "ke.php" which other files include -- particularly all functions that load data from or save data to files or alter folders or save info on the most recently used snippet ID. DesignKE should avoid reading data from disk that it does not have to. For example, it should never read an entire file into memory (unless it has to get at the data in the last line of the file). It should also open files at the beginning of a search and never close them until everything is displayed. One strategy might involve using Experiments:
Constants
Functions
Tasksedit.php: Load snippet/keywords into editor// $ID received <textarea cols="80" rows="24"><?php $file = '../s/'.idhigh($ID).'/'.idlow($ID); $lines = file_get_contents($file); // get two parts separated by first tab in $lines // do something with first part (keywords) // echo second part into textarea ?></textarea> // More likely we do "echo loadsnip($ID)" which is // defined in another file "ke.php" we include here. // Load keywords with "echo loadkeys($ID)". List snippet versions (in restore.php)Load snippet version into edit.php (from restore.php)Find next snippet with specific keywordsFind next snippet with specific phrases in textFAQs
|