In 6.1.0 beta 1, you were introduced to the OpenFileAs* and Write* subroutines.
Many people still don't use them. Please start now.
USE OF DIRECT OPEN(), LOCK(), PRINT, UNLOCK() AND CLOSE() ON FILEHANDLES IS NOW DIRECTLY FORBIDDEN WITHHIN THE UBB SOURCE CODE.print() is still fine to stdout (i.e. printing HTML to the browser)
If at all possible, you should use the existing file handling routines for all your I/O needs:
The existing
READ routines are:
my @file = OpenFileAsArray($filename);Opens $filename as an array. Returns an empty array if the file does not exist.
my @file = OpenFileAsArray2($filename);Opens $filename as an array. Dies if the file does not exist.
my $reference_to_hash = OpenFileAsHash($filename, $delimiter);Opens a file as an array, then splits each line on $delimiter, making the left side the key and the right side the value. Returns a reference to the created hash. Useful for turning things like memberslist into hashes.
my $string = OpenFileAsString($filename);my $string = OpenFileAsVar($filename);The same function. Both return $filename as unchomped string $string.
&OpenFileToSTDOUT($filename);Opens the selected file and prints it directly to the user. Useful for serving cache pages.
The existing
WRITE routines are:
&WriteFileAsArray($filename, @unchomped_or_chomped_array);Writes array to disk, as $filename. Each element in the array will be followed by a n. It doesn't matter if the array has been chomped or not.
&WriteFileAsHashKV($filename, $delimiter, $reference_to_hash);&WriteFileAsHashVK($filename, $delimiter, $reference_to_hash);Writes a one dimensional hash to disk. KV writes $key$delimiter$value, VK writes $value$delimiter$key. Useful for handling a memberslist hash opened using OpenFileAsHash.
&WriteFileAsString($filename, $string);Writes $string to $filename.
&WriteHashToFile($filename, $name_of_hash, $reference_to_hash);Writes a single hash to file for retrieval using do/require/RequireCode, etc, using said filename. Uses our own copy of Data:
:Dumper, not a custom routine, so you could, in theory, pass any data structures you wanted, such as UBB::FileHandler objects.
&WriteHashesToFile($filename, $array_ref_containing_hash_names, $array_ref_containing_hash_refs);Same as WriteHash, but this does multiple hashes, i.e.:
&AppendFileAsString($filename, $string);Appends $string to $filename. You will need to handle your own newlines. See the admin logging functions for an example.
&AppendFileAsArray($filename, @unchomped_or_chomped_array);Appends the array to $filename. This manages your newlines, and assumes the last line in the file is a newline if you want it to work right.
There are also
special routines for handling member and topic data:
my @user_profile = &OpenProfile($user_number);Returns the user profile for user $user_number. Returns an empty array if the user does not exist, or may return an error. Check memberslist for the guy first.
&WriteMemberProfile($user_number, @user_profile);Writes the user profile data back out to the profile.
Do not use any other routines to ever handle member data. Why? Becuase then you can replace both of those routines with your own custom creations to, say, talk to an RDBMS.
my @raw_thread_data = &OpenTopic($topic_number, $forum_number);&WriteTopic($forum_number, $topic_number, @raw_thread_data);Same as above - reads and writes to a topic file. And again, same as above,
do not use any other routines to ever handle topic data.
If, for some odd reason, those routines just won't work for you, and you need to do your own I/O, you MUST use the new FileHandler methods.
During init, the folowing call is made:
$filehandle = new UBB::FileHandler(%vars_config);This creates a new file handler. $filehandle is globalized via use vars.
To open a new file:
my $handle = $filehandle->open('type', 'mode', "filepath");Valid modes are:
readonly, writeonly, readwrite, writeappend
I think those are generally self explanitory.
Valid types are:
cache, index, lock, thread, forumd, member, hash, hashes, flat, file
Please use them as appropriate:
cache - Files in the noncgi/cache-number/ directory
index - Files in the noncgi/cache-number/search_index directory
lock - Files in the noncgi/cache-number/lock directory
thread - Threads (no prepended directory)
forumd - Forum meta data (lasttime/lastnumber/.threads/forum_thread_data)
member - Member profiles
hash - A file containing a single hash to be do/require()d later
hashes - A file containing one or more hashes to be do/require()d later
flat - A generic flat data file
file - A generic file
The following types have the directory name prepended within the I/O routine and do not need to have the path prepended:
cache (noncgi/cache-cache_pw)
cache (noncgi/cache-cache_pw/search_index)
lock (noncgi/cache-cache_pw/lock)
member (members)
Those must be passed the filename and path relative to that base. All others must be passed the full file path.
Currently the only special types that are actually being USED are hash/hashes, cache, member, and lock. The other types will be phased in for 6.2.
Anyway, back to the lesson.
$handle->print() - prints the line (scalar) or lines (list) passed through. Writing on a readonly file produces fatal errors, so don't do it.
Requires an exclusive lock.
$handle->truncate() - truncates the file to 0, 0. Truncating a readonly file produces fatal errors, so don't do it.
Requires an exclusive lock.
$handle->relock() - relocks the file to 'EX', 'SH', or 'UN'. Use with care, as it will die with a fatal error if the lock fails. You can not 'EX' a file that is not open for writing, nor can you 'SH' a file that's not open for reading. You can safely open a file for readwrite if you only intend to read but need an exclusive lock.
$handle->readline() - reads one line from the file and returns it, unchomped
$handle->readfile() - reads the entire file and returns it, unchomped
$handle->readfile_asarray() - reads the entire file and returns it (unchomped?) as an array split on newlines
Once you're done,
$filehandle->close($handle). Be careful there - you're telling the filehandler object to close the currently open filehandle. You can call close on the handle itself, and it will do so, but it will not remove the record from the filehandler object, meaning that instance of the UBB will keep the exclusive lock on the central lockfile. Don't do that.
Any and all hacks produced for 6.1.0-br2 MUST COMPLY with these open rules. Those that do not will receive massive criticism from yours truely and will be forced into compliance. Hacks that contain standalone scripts (i.e. ones that do not include UBB libraries, or do not run as part of the UBB script set) **MUST** establish a shared and exclusive lock on the global lock file as required. If you don't want to code your own routines, use the UBB::FileHandle(r) routines in your script:
You might also need to pull in public_common, or at least reimplement all the subroutines used there (&StandardHTML, &StandardHTML2, etc)
If you're a REAL code hacker (as opposed to just a tinkerer), you might want to explore the guts of ubb_lib_filehandle and ubb_lib_filehandler to see what they can potentially do.
Failure to use the new library may result in extremely unexpected results (i.e. your hack not playing well and being responsible for file corruption)
If you have any questions regarding these functions and the like, go ahead and post...