Difference between revisions of "Beginner's Guide to Programming"
Line 6: | Line 6: | ||
==Hello, World== | ==Hello, World== | ||
− | The first program you write in any computer language is "Hello World", and here it is in Geeklog. | + | The first program you write in any computer language is "Hello World", and here it is in Geeklog. This is saved in a file "hello.php" in Geeklog's "public_html" directory, and so is surfable at http://www.example.com/hello.php |
<pre> | <pre> | ||
Line 28: | Line 28: | ||
==Security== | ==Security== | ||
− | Speaking of the powerful Geeklog security model (one of the key reasons I originally chose Geeklog for my sites), let's alter the hello world program such that any user in the " | + | Speaking of the powerful Geeklog security model (one of the key reasons I originally chose Geeklog for my sites), let's alter the hello world program such that any user in the "geeker" user group will see the "hello world" message, but anyone not in that group (which includes users not logged in) will get a "permission denied" error. |
<pre> | <pre> | ||
Line 37: | Line 37: | ||
$display = COM_siteHeader(); | $display = COM_siteHeader(); | ||
− | if ( SEC_inGroup( ' | + | if ( SEC_inGroup( 'geeker' ) ) |
$display .= "Hello World"; | $display .= "Hello World"; | ||
else | else | ||
Line 60: | Line 60: | ||
$display = COM_siteHeader(); | $display = COM_siteHeader(); | ||
− | if ( ! SEC_inGroup( ' | + | if ( ! SEC_inGroup( 'geeker' ) ) |
{ | { | ||
$display .= "Access Denied"; | $display .= "Access Denied"; | ||
Line 79: | Line 79: | ||
</pre> | </pre> | ||
− | The big difference in this version of the program is that right at the top of the program we test for group permissions, and if the users does not have them we display the site footer, then exit. So a user not in the ' | + | The big difference in this version of the program is that right at the top of the program we test for group permissions, and if the users does not have them we display the site footer, then exit. So a user not in the 'geeker' group will end right there and never see what the rest of the program does. Very simple, but very powerful! This is precisely how you control access to you pages in Geeklog! |
==Where to put it== | ==Where to put it== | ||
− | If you are only writing a small program, then sticking a single file in the public_html directory as shown above will work fine. As soon as you get to the point, however, when you start having your own include files and so on, you probably want to create a directory for it. In our case we could create a directory in "public_html" called "hello", and then create a file "index.php" with the above program. | + | If you are only writing a small program, then sticking a single file in the public_html directory as shown above will work fine. As soon as you get to the point, however, when you start having your own include files and so on, you probably want to create a directory for it. In our case we could create a directory in "public_html" called "hello", and then create a file "index.php" with the above program. This will require a very minor change to the original program - see if you can pick it out before peeking : |
<pre> | <pre> | ||
Line 103: | Line 103: | ||
Yup, that's right, we had to add "../" to the "lib-common.php" in the "require_once" (which BTW is a type of "include" in PHP). The reason is simple : lib-common.php lives in public_html, and our first program was in that directory as well. This new program is in a subdirectory of public_html, so we have to go to the parent directory to get our include file. | Yup, that's right, we had to add "../" to the "lib-common.php" in the "require_once" (which BTW is a type of "include" in PHP). The reason is simple : lib-common.php lives in public_html, and our first program was in that directory as well. This new program is in a subdirectory of public_html, so we have to go to the parent directory to get our include file. | ||
− | If you want to keep your geeklog installation "pure", as I usually do, you can also put your program directory somewhere outside of the geeklog directory, and use directives for your webserver to map that directory into the web space of your geeklog installation. That's easier than it sounds - with Apache just use the "Alias" directive | + | If you want to keep your geeklog installation "pure", as I usually do, you can also put your program directory somewhere outside of the geeklog directory, and use directives for your webserver to map that directory into the web space of your geeklog installation. That's easier than it sounds - with Apache just use the "Alias" directive in your apache config file, like this : |
<pre> | <pre> | ||
Line 119: | Line 119: | ||
This is a bit of an advanced topic which in some ways is out of place at this point, but just about everyone who knows Geeklog and has used it a bit, knows about [[[[Plugin Developers Handbook|Geeklog plugins]]. And when writing your own Geeklog programs, this will obviously be something in your mind. Not all Geeklog programs are plugins - and the above examples are not. Plugins involve writing your program in a specific way, and defining specific functions which Geeklog will expect to find. It also involves making some entries in the Geeklog database to let Geeklog know that your plugin is there. | This is a bit of an advanced topic which in some ways is out of place at this point, but just about everyone who knows Geeklog and has used it a bit, knows about [[[[Plugin Developers Handbook|Geeklog plugins]]. And when writing your own Geeklog programs, this will obviously be something in your mind. Not all Geeklog programs are plugins - and the above examples are not. Plugins involve writing your program in a specific way, and defining specific functions which Geeklog will expect to find. It also involves making some entries in the Geeklog database to let Geeklog know that your plugin is there. | ||
− | In general if you want to use the Geeklog comment engine, the Geeklog search engine (i.e. integrate your program data into the search feature of Geeklog), or the Geeklog submission engine, you must write a plugin. Otherwise you can just write code. Size doesn't matter. | + | In general if you want to use the Geeklog comment engine, the Geeklog search engine (i.e. integrate your program data into the search feature of Geeklog), or the Geeklog submission engine, you must write a plugin. Otherwise you can just write code. Size doesn't matter. There is no limit after which you have to make it a plugin. |
==Some Odds and Ends== | ==Some Odds and Ends== | ||
Line 125: | Line 125: | ||
A couple of more quick points on some basic Geeklog stuff | A couple of more quick points on some basic Geeklog stuff | ||
− | <li> the $_USER array comes pre-populated for you by Geeklog. If $_USER['uid'] is greater than 1, then you know your user is logged on. Otherwise they are anonymous. So in the above example if you wanted to test for "logged on user" rather than "member of | + | <li> the $_USER array comes pre-populated for you by Geeklog. If $_USER['uid'] is greater than 1, then you know your user is logged on. Otherwise they are anonymous. So in the above example if you wanted to test for "logged on user" rather than "member of geeker group", just change the 'if' statement accordingly. This array contains all of the user table from geeklog, the next most useful subscript being $_USER['username'] |
<li> the $_CONF array contains everything you set in your config.php, if you need it. Just check config.php for what all is there. | <li> the $_CONF array contains everything you set in your config.php, if you need it. Just check config.php for what all is there. | ||
<li> both of the above arrays are global, and as such if you use them in a function you must declare them in the function with the 'global' directive, as is normal for PHP. Outside of any function in the main body of the program they can be just used. | <li> both of the above arrays are global, and as such if you use them in a function you must declare them in the function with the 'global' directive, as is normal for PHP. Outside of any function in the main body of the program they can be just used. | ||
Line 133: | Line 133: | ||
We've already seen two of the most widely used functions that Geeklog has to offer - COM_siteHeader() and COM_siteFooter(). It is important to note with this that there are optional parameters you can pass to each of them to achieve certain results. COM_siteHeader() displays the header and the left blocks, while it's partner controls the footer and the right blocks. By default COM_siteHeader() displays the left blocks, and by default COM_siteFooter() does not display the right blocks. Check the source code in lib-common.php for details on how to change this behavior. | We've already seen two of the most widely used functions that Geeklog has to offer - COM_siteHeader() and COM_siteFooter(). It is important to note with this that there are optional parameters you can pass to each of them to achieve certain results. COM_siteHeader() displays the header and the left blocks, while it's partner controls the footer and the right blocks. By default COM_siteHeader() displays the left blocks, and by default COM_siteFooter() does not display the right blocks. Check the source code in lib-common.php for details on how to change this behavior. | ||
− | Another set of similar workhorse functions which are also defined in lib-common.php along with the aforementioned functions are COM_startBlock() and COM_endBlock(). COM_startBlock() accepts 3 optional parameters : title, helpfile and template. | + | Another set of similar workhorse functions which are also defined in lib-common.php along with the aforementioned functions are COM_startBlock() and COM_endBlock(). COM_startBlock() accepts 3 optional parameters : title, helpfile and template. The most useful and almost always used is title, which is a text string which will appear in the title bar of the block. If a helpfile is specified, Geeklog will display the help question mark icon and link to a help file for that block. And by default the 'blockheader.thtml' template is used unless another is specified. COM_endBlock() '''must''' be called once for each call to COM_startBlock(), and it's only optional parameter is template, the default being blockfooter.thtml. |
Blocks can be nested inside of each other, which is obvious by simply looking at just about any geeklog website. | Blocks can be nested inside of each other, which is obvious by simply looking at just about any geeklog website. | ||
Line 158: | Line 158: | ||
</pre> | </pre> | ||
− | When using nested blocks inside of HTML tables, one simply has to be certain to call COM_endBlock() in the | + | When using nested blocks inside of HTML tables, one simply has to be certain to call COM_endBlock() in the right place since these functions output HTML tables as well, and otherwise the display may not render properly. |
<pre> | <pre> | ||
Line 192: | Line 192: | ||
The great advantage of using these two functions is that whenever the site admin or user changes their Geeklog theme, your GUI will change to match. Your program will always retain the same look-and-feel of the site in general. | The great advantage of using these two functions is that whenever the site admin or user changes their Geeklog theme, your GUI will change to match. Your program will always retain the same look-and-feel of the site in general. | ||
− | There are also some useful form functions found in lib-common.php which come in very handy and make life a bit easier. '''COM_optionList( $table, $selection, $selected='', $sortcol=1 )'''. This creates an HTML "<option" list generated from the given table, using the passed variable "$selected" in the SELECT statement of the HTML query. See source code for a better idea of what the function does, but it is very useful. | + | There are also some useful HTML form functions found in lib-common.php which come in very handy and make life a bit easier. '''COM_optionList( $table, $selection, $selected='', $sortcol=1 )'''. This creates an HTML "<option" list generated from the given table, using the passed variable "$selected" in the SELECT statement of the HTML query. See source code for a better idea of what the function does, but it is very useful. |
In a similar vein, '''COM_checkList( $table, $selection, $where='', $selected='' )''' creates a list of check boxes from the given table, with the given select and where clauses being passed to the SQL statement inside the function. | In a similar vein, '''COM_checkList( $table, $selection, $where='', $selected='' )''' creates a list of check boxes from the given table, with the given select and where clauses being passed to the SQL statement inside the function. | ||
Line 198: | Line 198: | ||
One more useful function is the '''COM_errorLog($logentry, $actionid = '') '''function which logs to the Geeklog logfile if $actionid is 1, or to the screen if it is set to 2. | One more useful function is the '''COM_errorLog($logentry, $actionid = '') '''function which logs to the Geeklog logfile if $actionid is 1, or to the screen if it is set to 2. | ||
− | '''COM_checkWords( $Message )''' gives you access to Geeklog's (somewhat rudementary) profanity filter. We find it to be | + | '''COM_checkWords( $Message )''' gives you access to Geeklog's (somewhat rudementary) profanity filter. We find it to be not terribly useful since if you include for example the word "cock" in your filter, you will also filter out the completely innocuous word "peacock". If you nonetheless want to use the geeklog profanity filter, simply do this : |
<pre> | <pre> | ||
Line 212: | Line 212: | ||
</pre> | </pre> | ||
− | In this example, inside the text of someprogram.php, if the PHP installation has "register_globals" turned on, the variable "$variable" will automagically exist in the program and will have the value "value". But there are certain security problems with using "register_globals" in PHP so a lot of people do not like to have it turned on. Unfortunately Geeklog requires that it be turned on (at least for now until the programmers get it rewritten to eliminate the need), so to mitigate the risks involved you can use special functions to obtain your query string variables. | + | The query string is the part after the question mark - the stuff you pass into your program. In this example, inside the text of someprogram.php, if the PHP installation has "register_globals" turned on, the variable "$variable" will automagically exist in the program and will have the value "value". But there are certain security problems with using "register_globals" in PHP so a lot of people do not like to have it turned on. Unfortunately Geeklog requires that it be turned on (at least for now until the programmers get it rewritten to eliminate the need), so to mitigate the risks involved you can use special functions to obtain your query string variables. |
Near the top of your program simply insert something like the following, first to define which are the only global variables your program expects to see, then finally to safely obtain the value of those variables : | Near the top of your program simply insert something like the following, first to define which are the only global variables your program expects to see, then finally to safely obtain the value of those variables : | ||
Line 223: | Line 223: | ||
==Using the Database== | ==Using the Database== | ||
− | Geeklog has a database abstraction layer which in theory makes it possible for you to use any database as the backend for it. Though in practice the Geeklog team has only implemented a backend for the popular MySQL database. In any case, when programming Geeklog you do not use the regular PHP database functions - instead you use the DB_ functions which behave almost idenically to the PHP functions that have similar names. | + | Geeklog has a database abstraction layer which in theory makes it possible for you to use any database as the backend for it. Though in practice the Geeklog team has only implemented a backend for the popular [http://www.mysql.com MySQL] database. In any case, when programming Geeklog you do not use the regular PHP database functions - instead you use the DB_ functions which behave almost idenically to the PHP functions that have similar names. |
− | Another important thing to note about Geeklog is that you should never use table names directly in your queries. Instead, you should use the $_TABLES global variable, and add your own table names to it if you make your own tables. The reason for this is simply that Geeklog allows the installer to specify a "table prefix", so if you use table names directly your code will not run on another Geeklog installation that uses a different table prefix. Even if you think you'll never want to run your code on | + | Another important thing to note about Geeklog is that you should never use table names directly in your queries. Instead, you should use the $_TABLES global variable, and add your own table names to it if you make your own tables. The reason for this is simply that Geeklog allows the installer to specify a "table prefix", so if you use table names directly your code will not run on another Geeklog installation that uses a different table prefix. Even if you think you'll never want to run your code on another Geeklog installation, we recommend you do things properly because you never do know. I've written code that I thought would never have to run in another installation, and sure enough 2 years later I have to go back and convert it all to use the $_TABLES array because now I do indeed want to run it on another installation that is using a different table prefix. |
− | One final very important thing to state about using the Geeklog database is that under no circumstances whatsoever should you ever alter the default Geeklog tables. One example of where you might be tempted to do this is if you want to track a specific option for users - you may be tempted to add a field or two to the Geeklog "users" table. Say you are writing a program "buysell" which allows users to enter items into the database to put them up for sale to other users. And when browsing the database to see what is for sale, you want each | + | One final very important thing to state about using the Geeklog database is that '''under no circumstances whatsoever should you ever alter the default Geeklog tables'''. One example of where you might be tempted to do this is if you want to track a specific option for users - you may be tempted to add a field or two to the Geeklog "users" table. Say for example you are writing a program "buysell" which allows users to enter items into the database to put them up for sale to other users. And when browsing the database to see what is for sale, you want each user to decide whether or not they want to see their own items. You may be tempted to add a boolean field "seeown" to the Geeklog users table, but don't do it! Instead, create your own table "buysell_userprefs" and add whatever fields you require to this new table. At very least we need a field for the userid - so we'll call it "bsp_uid", and we need a field for "see your own items" so we'll call it "bsp_seeown". |
− | In general we like to give table fields names that have an abbreviation of the table name at the beginning of every field. So in our case this is a table which contains "buy sell preferences" for each user, so we'll name all the fields "bsp_". This is optional, but we've found it to be a good practice so that you do not | + | In general we like to give table fields names that have an abbreviation of the table name at the beginning of every field. So in our case this is a table which contains "buy sell preferences" for each user, so we'll name all the fields "bsp_". This is optional, but we've found it to be a good practice so that you do not end up with fields from various tables with the same name - something that can under circumstances cause problems in your queries, or unexpected results. |
===Adding to $_TABLES=== | ===Adding to $_TABLES=== | ||
Line 269: | Line 269: | ||
// there should be precisely one entry for each user | // there should be precisely one entry for each user | ||
// otherwise you may want to flag an error condition | // otherwise you may want to flag an error condition | ||
+ | // or you may want to alternately check to see if this | ||
+ | // value is less than 1 first, in which case they user | ||
+ | // has not yet set their preferences | ||
} | } | ||
$bsp = DB_fetchArray( $result ); | $bsp = DB_fetchArray( $result ); | ||
Line 288: | Line 291: | ||
Wow! THere's lots going on in this program! A lot more than what we might have expected! First and foremost note that there are lots of potential error conditions to check for, when using the Geeklog database. This is no different from just programming MySQL with the normal PHP functions, actually. It is always a best practice to check for error conditions and react accordingly. | Wow! THere's lots going on in this program! A lot more than what we might have expected! First and foremost note that there are lots of potential error conditions to check for, when using the Geeklog database. This is no different from just programming MySQL with the normal PHP functions, actually. It is always a best practice to check for error conditions and react accordingly. | ||
− | Before we looked up the | + | Before we looked up the user's preference, we of course first did a check to make sure they were logged on, and if not we exited. Then, you can see how we added our table to the $_TABLES global variable, and then inside of the SELECT statement used the $_TABLES variable to ensure our code is portable. If you wanted to move this to another system you do not have to change a thing! |
As for the specific DB_ functions we used, they behave in the same way as the PHP MySQL functions with similar names. If you aren't familiar with how they work, check the Geeklog source code as well as the PHP manual. For a full listing of all the DB_ functions available to you, check out /path/to/geeklog/system/lib-database.php | As for the specific DB_ functions we used, they behave in the same way as the PHP MySQL functions with similar names. If you aren't familiar with how they work, check the Geeklog source code as well as the PHP manual. For a full listing of all the DB_ functions available to you, check out /path/to/geeklog/system/lib-database.php | ||
Line 294: | Line 297: | ||
==Support and Such== | ==Support and Such== | ||
− | + | The best place for Geeklog support is of course [http://www.geeklog.net the main Geeklog site]. But there are a few other great places to check including [http://www.squatty.com Squatty] and [http://www.portalparts.com Portal Parts]. Squatty and Blaine are hard-core Geeklog developers and are responsible for several popular themes, plugins and hacks. | |
− | If you want to report a bug or request a feature, set yourself up an account [http://project.geeklog.net/tracker/?atid=105&group_id=6&func=browse here] and do so. If they don't know it is broken, the cannot fix it. I've reported several bugs and have had them fixed prompty. I've also tracked down and fixed several bugs and simply submitted the code which was accepted. And I've also requested several | + | If you want to report a bug or request a feature, set yourself up an account [http://project.geeklog.net/tracker/?atid=105&group_id=6&func=browse here] and do so. If they don't know it is broken, the cannot fix it. I've reported several bugs and have had them fixed prompty. I've also tracked down and fixed several bugs and simply submitted the code which was accepted. And I've also requested several features which have been added over the years at my request. The Geeklog development team is small, but very dedicated and they love to get feedback from the user base. |
Revision as of 13:22, 1 July 2004
By Alan McKay
Geeklog is a powerful weblog (blog) content management system (CMS) which is written in the popular programming language <a PHP, and uses the popular MySQL database. While Geeklog is powerful enough that many users will not have a need to write their own applications for it, it is flexible enough to allow those who do require extra functionality to do so easily. These people write there programs in PHP, with some minor restrictions and using the Geeklog function library.
Contents
Hello, World
The first program you write in any computer language is "Hello World", and here it is in Geeklog. This is saved in a file "hello.php" in Geeklog's "public_html" directory, and so is surfable at http://www.example.com/hello.php
<?php require_once( 'lib-common.php' ); $display = COM_siteHeader(); $display .= "Hello World"; $display .= COM_siteFooter(); echo $display; ?>
There are a few important things to be noted from the given program.
Security
Speaking of the powerful Geeklog security model (one of the key reasons I originally chose Geeklog for my sites), let's alter the hello world program such that any user in the "geeker" user group will see the "hello world" message, but anyone not in that group (which includes users not logged in) will get a "permission denied" error.
<?php require_once( 'lib-common.php' ); $display = COM_siteHeader(); if ( SEC_inGroup( 'geeker' ) ) $display .= "Hello World"; else $display .= "Access Denied"; $display .= COM_siteFooter(); echo $display; ?>
To check out the full range of security functions available to you, and how to use them, read the /path/to/geeklog/system/lib-security.php file, which is where they are implemented.
Though the above code format is a bit clunky and not terribly useful, so let's make another change which shows us how most programs deal with group permissions issues.
<?php require_once( 'lib-common.php' ); $display = COM_siteHeader(); if ( ! SEC_inGroup( 'geeker' ) ) { $display .= "Access Denied"; $display .= COM_siteFooter(); echo $display; exit; } $display .= "Hello World"; // do some other stuff here $display .= COM_siteFooter(); echo $display; ?>
The big difference in this version of the program is that right at the top of the program we test for group permissions, and if the users does not have them we display the site footer, then exit. So a user not in the 'geeker' group will end right there and never see what the rest of the program does. Very simple, but very powerful! This is precisely how you control access to you pages in Geeklog!
Where to put it
If you are only writing a small program, then sticking a single file in the public_html directory as shown above will work fine. As soon as you get to the point, however, when you start having your own include files and so on, you probably want to create a directory for it. In our case we could create a directory in "public_html" called "hello", and then create a file "index.php" with the above program. This will require a very minor change to the original program - see if you can pick it out before peeking :
<?php require_once( '../lib-common.php' ); $display = COM_siteHeader(); $display .= "Hello World"; $display .= COM_siteFooter(); echo $display; ?>
Yup, that's right, we had to add "../" to the "lib-common.php" in the "require_once" (which BTW is a type of "include" in PHP). The reason is simple : lib-common.php lives in public_html, and our first program was in that directory as well. This new program is in a subdirectory of public_html, so we have to go to the parent directory to get our include file.
If you want to keep your geeklog installation "pure", as I usually do, you can also put your program directory somewhere outside of the geeklog directory, and use directives for your webserver to map that directory into the web space of your geeklog installation. That's easier than it sounds - with Apache just use the "Alias" directive in your apache config file, like this :
Alias /hello/ "/path/to/your/hello/"
Of course, this means that your require_once statement will have to contain the full path to lib-common.php
require_once( '/path/to/geeklog/public_html/lib-common.php' );
To Plug it in, or not
This is a bit of an advanced topic which in some ways is out of place at this point, but just about everyone who knows Geeklog and has used it a bit, knows about [[Geeklog plugins. And when writing your own Geeklog programs, this will obviously be something in your mind. Not all Geeklog programs are plugins - and the above examples are not. Plugins involve writing your program in a specific way, and defining specific functions which Geeklog will expect to find. It also involves making some entries in the Geeklog database to let Geeklog know that your plugin is there.
In general if you want to use the Geeklog comment engine, the Geeklog search engine (i.e. integrate your program data into the search feature of Geeklog), or the Geeklog submission engine, you must write a plugin. Otherwise you can just write code. Size doesn't matter. There is no limit after which you have to make it a plugin.
Some Odds and Ends
A couple of more quick points on some basic Geeklog stuff
Functions, Bring Me Functions!
We've already seen two of the most widely used functions that Geeklog has to offer - COM_siteHeader() and COM_siteFooter(). It is important to note with this that there are optional parameters you can pass to each of them to achieve certain results. COM_siteHeader() displays the header and the left blocks, while it's partner controls the footer and the right blocks. By default COM_siteHeader() displays the left blocks, and by default COM_siteFooter() does not display the right blocks. Check the source code in lib-common.php for details on how to change this behavior.
Another set of similar workhorse functions which are also defined in lib-common.php along with the aforementioned functions are COM_startBlock() and COM_endBlock(). COM_startBlock() accepts 3 optional parameters : title, helpfile and template. The most useful and almost always used is title, which is a text string which will appear in the title bar of the block. If a helpfile is specified, Geeklog will display the help question mark icon and link to a help file for that block. And by default the 'blockheader.thtml' template is used unless another is specified. COM_endBlock() must be called once for each call to COM_startBlock(), and it's only optional parameter is template, the default being blockfooter.thtml.
Blocks can be nested inside of each other, which is obvious by simply looking at just about any geeklog website.
<?php require_once( 'lib-common.php' ); $display = COM_siteHeader(); $display .= COM_startBlock("Outer Block") . "This text should be inside the outer block but outside the inner block" . COM_startBlock("Inner Block") . "This text should be inside the inner block" . COM_endBlock() . COM_endBlock(); $display .= COM_siteFooter(); echo $display; ?>
When using nested blocks inside of HTML tables, one simply has to be certain to call COM_endBlock() in the right place since these functions output HTML tables as well, and otherwise the display may not render properly.
<?php require_once( 'lib-common.php' ); $display = COM_siteHeader(); $display .= COM_startBlock("Outer Block") . "This text should be inside the outer block but outside the inner blocks" . "<table align=center width=100% border=0>" . "<tr><td align=center width=50%>" . COM_startBlock("Left Inner Block") . "This text should be inside the left inner block" . COM_endBlock() . "</td>" . "<td align=center width=50%>" . COM_startBlock("Left Inner Block") . "This text should be inside the right inner block" . COM_endBlock() . "</td></tr></table>" . "This text should be below the inner blocks but inside the outer block" . COM_endBlock(); $display .= COM_siteFooter(); echo $display; ?>
The great advantage of using these two functions is that whenever the site admin or user changes their Geeklog theme, your GUI will change to match. Your program will always retain the same look-and-feel of the site in general.
There are also some useful HTML form functions found in lib-common.php which come in very handy and make life a bit easier. COM_optionList( $table, $selection, $selected=, $sortcol=1 ). This creates an HTML "<option" list generated from the given table, using the passed variable "$selected" in the SELECT statement of the HTML query. See source code for a better idea of what the function does, but it is very useful.
In a similar vein, COM_checkList( $table, $selection, $where=, $selected= ) creates a list of check boxes from the given table, with the given select and where clauses being passed to the SQL statement inside the function.
One more useful function is the COM_errorLog($logentry, $actionid = ) function which logs to the Geeklog logfile if $actionid is 1, or to the screen if it is set to 2.
COM_checkWords( $Message ) gives you access to Geeklog's (somewhat rudementary) profanity filter. We find it to be not terribly useful since if you include for example the word "cock" in your filter, you will also filter out the completely innocuous word "peacock". If you nonetheless want to use the geeklog profanity filter, simply do this :
$text = COM_checkWords( $text )
COM_mail( $to, $subject, $message, $from = , $html = false, $priority = 0 ) does exactly what the name suggests and lets you send mail to someone.
THere are far too many functions in lib-common.php to discuss here, so we'll end off with two very important ones which can be used for accessing query-string variables. What's a query string? If you have a URL like this :
http://www.example.com/someprogram.php?variable=value&othervariable=othervalue
The query string is the part after the question mark - the stuff you pass into your program. In this example, inside the text of someprogram.php, if the PHP installation has "register_globals" turned on, the variable "$variable" will automagically exist in the program and will have the value "value". But there are certain security problems with using "register_globals" in PHP so a lot of people do not like to have it turned on. Unfortunately Geeklog requires that it be turned on (at least for now until the programmers get it rewritten to eliminate the need), so to mitigate the risks involved you can use special functions to obtain your query string variables.
Near the top of your program simply insert something like the following, first to define which are the only global variables your program expects to see, then finally to safely obtain the value of those variables :
COM_setArgNames(array('variable','othervariable')); $variable = COM_getArgument('variable'); $othervariable = COM_getArgument('othervariable');
Using the Database
Geeklog has a database abstraction layer which in theory makes it possible for you to use any database as the backend for it. Though in practice the Geeklog team has only implemented a backend for the popular MySQL database. In any case, when programming Geeklog you do not use the regular PHP database functions - instead you use the DB_ functions which behave almost idenically to the PHP functions that have similar names.
Another important thing to note about Geeklog is that you should never use table names directly in your queries. Instead, you should use the $_TABLES global variable, and add your own table names to it if you make your own tables. The reason for this is simply that Geeklog allows the installer to specify a "table prefix", so if you use table names directly your code will not run on another Geeklog installation that uses a different table prefix. Even if you think you'll never want to run your code on another Geeklog installation, we recommend you do things properly because you never do know. I've written code that I thought would never have to run in another installation, and sure enough 2 years later I have to go back and convert it all to use the $_TABLES array because now I do indeed want to run it on another installation that is using a different table prefix.
One final very important thing to state about using the Geeklog database is that under no circumstances whatsoever should you ever alter the default Geeklog tables. One example of where you might be tempted to do this is if you want to track a specific option for users - you may be tempted to add a field or two to the Geeklog "users" table. Say for example you are writing a program "buysell" which allows users to enter items into the database to put them up for sale to other users. And when browsing the database to see what is for sale, you want each user to decide whether or not they want to see their own items. You may be tempted to add a boolean field "seeown" to the Geeklog users table, but don't do it! Instead, create your own table "buysell_userprefs" and add whatever fields you require to this new table. At very least we need a field for the userid - so we'll call it "bsp_uid", and we need a field for "see your own items" so we'll call it "bsp_seeown".
In general we like to give table fields names that have an abbreviation of the table name at the beginning of every field. So in our case this is a table which contains "buy sell preferences" for each user, so we'll name all the fields "bsp_". This is optional, but we've found it to be a good practice so that you do not end up with fields from various tables with the same name - something that can under circumstances cause problems in your queries, or unexpected results.
Adding to $_TABLES
As already mentioned, if you define your own tables, you have to add them to the global $_TABLES variable.
$_TABLES['buysell_userprefs'] = $_DB_table_prefix . 'buysell_userprefs';
Note that we've included the Geeklog global variable for table prefix, so that our code will work in all Geeklog installations. And of course you need one line for every table you are adding to the Geeklog database. And finally, like any global variable in Geelog you must declare it global in a function if you want to use it in that function.
When doing a plugin you usually put this into the config.php for your plugin. If not doing a plugin you have several options on where to put it, depending upon how you have your code organised. If you have one big file, then put it at the top of that file. If you have an include file that gets included by all the programs you are writing, put it there. Basically you have to put it whereever you can that will ensure it gets executed by all of your programs and is visible by all of your programs.
Get on with it!
And finally we can show you how to put it all together. Let's write a simple little program that does nothing more than show you what your 'bsp_seeown' preference is set to.
<?php require_once('lib-common.php'); $display = COM_siteHeader(); if ( $_USER['uid'] < 2 ) { $display .= "You are not logged in"; $display .= COM_siteFooter(); echo $display; exit; } $_TABLES['buysell_userprefs'] = $_DB_table_prefix . 'buysell_userprefs'; $sql = "SELECT bsp_seeown FROM {$_TABLES['buysell_userprefs']} " . " WHERE {$_TABLES['buysell_userprefs']}.bsp_uid = {$_USER['uid']} "; $result = DB_query( $sql ); if ( ! $result ) { // some error condition and possibly exit } if ( DB_numRows( $result ) <> 1 ) { // there should be precisely one entry for each user // otherwise you may want to flag an error condition // or you may want to alternately check to see if this // value is less than 1 first, in which case they user // has not yet set their preferences } $bsp = DB_fetchArray( $result ); if ( ! $bsp ) { // some error condition } $display .= COM_startBlock("Your Preference is") . $bsp['bsp_seeown'] . COM_endBlock(); $display .= COM_siteFooter(); echo $display; ?>
Wow! THere's lots going on in this program! A lot more than what we might have expected! First and foremost note that there are lots of potential error conditions to check for, when using the Geeklog database. This is no different from just programming MySQL with the normal PHP functions, actually. It is always a best practice to check for error conditions and react accordingly.
Before we looked up the user's preference, we of course first did a check to make sure they were logged on, and if not we exited. Then, you can see how we added our table to the $_TABLES global variable, and then inside of the SELECT statement used the $_TABLES variable to ensure our code is portable. If you wanted to move this to another system you do not have to change a thing!
As for the specific DB_ functions we used, they behave in the same way as the PHP MySQL functions with similar names. If you aren't familiar with how they work, check the Geeklog source code as well as the PHP manual. For a full listing of all the DB_ functions available to you, check out /path/to/geeklog/system/lib-database.php
Support and Such
The best place for Geeklog support is of course the main Geeklog site. But there are a few other great places to check including Squatty and Portal Parts. Squatty and Blaine are hard-core Geeklog developers and are responsible for several popular themes, plugins and hacks.
If you want to report a bug or request a feature, set yourself up an account here and do so. If they don't know it is broken, the cannot fix it. I've reported several bugs and have had them fixed prompty. I've also tracked down and fixed several bugs and simply submitted the code which was accepted. And I've also requested several features which have been added over the years at my request. The Geeklog development team is small, but very dedicated and they love to get feedback from the user base.