<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
  <title>dfa</title>
  <link>http://dfaddons.com/</link>
  <description>dfaddons</description>
  <language>en-us</language>
  <pubDate>Wed, 25 Aug 2010 01:40:32 GMT</pubDate>
  <ttl>1440</ttl>
  <generator>CPG-Nuke Dragonfly</generator>
  <copyright>dfa</copyright>
  <category></category>
  <docs>http://backend.userland.com/rss</docs>
  <image>
    <url>http://dfaddons.com/images/dfaddons.png</url>
    <title>dfa</title>
    <link>http://dfaddons.com/</link>
  </image>

<item>
  <title>AccountPlus,,,   almost there...</title>
  <link>http://dfaddons.com/ForumsPro/viewtopic/p=198.html#198</link>
  <description>Themes are ready to roll, there might be some minor detail that needs to be fixed. Other than that the theme are good to go.</description>
  <pubDate>Wed, 25 Aug 2010 01:40:32 GMT</pubDate>
  <guid>http://dfaddons.com/ForumsPro/viewtopic/p=198.html#198</guid>
</item><item>
  <title>O,K,   new changes to dragonfly cms in 2 years,,,</title>
  <link>http://dfaddons.com/ForumsPro/viewtopic/p=197.html#197</link>
  <description>LOL! Bring back old memories. Oh well. I hope we do not go that route again.</description>
  <pubDate>Wed, 25 Aug 2010 01:37:36 GMT</pubDate>
  <guid>http://dfaddons.com/ForumsPro/viewtopic/p=197.html#197</guid>
</item><item>
  <title>Half Past Human March 2010 - Predictions Of Oil Disaster</title>
  <link>http://dfaddons.com/ForumsPro/viewtopic/p=147.html#147</link>
  <description>Always interested in alternative things, and time perception and the hyperchroniacs is one of them, anyone seen ravenous?

6/24/10 P-1 Webbot Clif High on Rense Radio 

Here is an interview and the entire show is available via mp3 audio and recommended for your listening enjoyment, if you have not heard yet, and/or you know about the web bot project and the research being done and how!

[youtube]-XD0z-de2i4[/youtube]</description>
  <pubDate>Tue, 06 Jul 2010 12:43:33 GMT</pubDate>
  <guid>http://dfaddons.com/ForumsPro/viewtopic/p=147.html#147</guid>
</item><item>
  <title>What does forumspro give more than default??</title>
  <link>http://dfaddons.com/ForumsPro/viewtopic/p=110.html#110</link>
  <description>try and see,  it does not cause problems with  the default forum and you can import that forum threads and posts into fpro.

try it out and look at the configuration and you will see the enhanced options..just make it admin only and do not import anything at first, and keep it in a test mode for you and if you decided to go with it, then uninstall resinstall and import data from forums...</description>
  <pubDate>Thu, 01 Jul 2010 11:40:54 GMT</pubDate>
  <guid>http://dfaddons.com/ForumsPro/viewtopic/p=110.html#110</guid>
</item><item>
  <title>DF Master Language Package</title>
  <link>http://dfaddons.com/ForumsPro/viewtopic/p=94.html#94</link>
  <description>It, like almost all others is a work in progress, working on getting projects established more, so everyone and anyone can be more pro-active in them and their status, etc.,

This package containts 20 Languages (Basic) for many versions of DF, 

Please back up current language, directory, before installing.

These are unzipped and compiled structure combined and then compressed back and ready for you to download and upload to your DF install, 

Estimated time:  Download/Upload = 1 hr +/-

If you notice any issues, please let us know! read&amp;nbsp;more.</description>
  <pubDate>Wed, 30 Jun 2010 14:43:11 GMT</pubDate>
  <guid>http://dfaddons.com/ForumsPro/viewtopic/p=94.html#94</guid>
</item><item>
  <title>Porting Applications to DF</title>
  <link>http://dfaddons.com/ForumsPro/viewtopic/p=88.html#88</link>
  <description>Porting Applications

http://dragonflycms.org/Wiki/id=87.html

Section 1: Database Queries

Database queries are the heart of just about every application written for a CMS such as CPG Dragonfly CMS™, therefore they come first.

SECURITY:
Some applications will run without converting queries to the abstraction layer, however the abstraction layer adds a level of protection, error reporting, and debugging that is essential to the workings and security of CPG Dragonfly CMS™. Not converting queries is *NOT* an option when porting an app to DragonflyCMS™.

Over the years, methods for accessing data in a database has changed drastically. Therefore, if the module you are porting is not kept current with current coding practices, this is where you will spend most of your time. CPG Dragonfly CMS™ uses the &quot;database abstraction layer&quot; method for querying the database, so every query must be converted to this newer method if it is not already coded that way. Other methods of querying data that you will more than likely see are what I will call the &quot;mysql API call method&quot; and the &quot;DBI sql layer method.&quot; Conversions for these will be outlined below:

Converting MySQL API Calls to the Database Abstraction Layer:

Consider the following bit of code:

PHP:
    mysql_connect(&quot;localhost&quot;, &quot;mysql_user&quot;, &quot;mysql_password&quot;) or
    die(&quot;Could not connect: &quot; . mysql_error());
    mysql_select_db(&quot;mydb&quot;);
    $result = mysql_query(&quot;SELECT id, name FROM mytable&quot;);
    while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
        printf(&quot;ID: %s  Name: %s&quot;, $row[0], $row[1]);
    }
    mysql_free_result($result);


Now we see it rewritten using the abstraction layer:

PHP:
       global $db;   // $db is the abstraction layer access object.
       $result = $db-&amp;gt;sql_query(&quot;SELECT id, name FROM mytable&quot;);
       while ($row = $db-&amp;gt;sql_fetchrow($result)) {
           printf(&quot;ID: %s  Name: %s&quot;, $row[&#039;id&#039;], $row[&#039;name&#039;]);
       }
       $db-&amp;gt;sql_freeresult($result);


For starters, we removed the mysql_connect() and mysql_select_db() calls as they are not needed when using the abstraction layer. After that, we give our application access to $db, the abstraction layer database access object. Since this object is in the global scope of the program, you will need to declare it global *IF* you are accessing it from within a function.

Next, we converted the query to the $db-&amp;gt;sql_query() format. This is fairly straight-forward.

Notice how when we converted mysql_fetch_array() to $db-&amp;gt;sql_fetchrow(), we only pass the $result parameter to $db-&amp;gt;sql_fetchrow. The abstraction layer handles the rest for us.

Finally, we converted mysql_free_result() to $db-&amp;gt;sql_freeresult(). It&#039;s good coding practice to free the results once you are done as it returns resources temporarily used by the database query back to the operating system. Many applications you see will *NOT* free results. This is simply poor coding practices and should be corrected while porting apps to CPG Dragonfly CMS™.

Converting DBI SQL Layer calls to the Database Abstraction Layer:

Take a look at this code:

PHP:
    global $dbi;
    $sql = &quot;select com_id, userid, date, comments, score from &quot;.
           $prefix.&quot;_MReviews_comments where rid=&#039;$rid&#039; ORDER BY date DESC&quot;;
    $result = sql_query($sql, $dbi);
    while(list($com_id, $uname, $date, $comments, $score) = sql_fetch_row($result, $dbi)) {
       echo &quot;on $date, $uname left the comment $comments\n&quot;;
    }


Now see it rewritten using the abstraction layer and cleaned up a bit:

PHP:
    global $db; // $db is the abstraction layer access object.
    $sql = &quot;SELECT com_id, userid, date, comments, score FROM &quot;.
           $prefix.&quot;_MReviews_comments WHERE rid=&#039;$rid&#039; ORDER BY date DESC&quot;;
    $result = $db-&amp;gt;sql_query($sql);
    while ($row = $db-&amp;gt;sql_fetchrow($result)) {
        $com_id = $row[&#039;com_id&#039;];
        $uname = $row[&#039;uname&#039;];
        $date = $row[&#039;date&#039;];
        $comments = $row[&#039;comments&#039;];
        echo &quot;on $date, $uname left the comment $comments\n&quot;;
    }
    $db-&amp;gt;sql_freeresult($result);


To convert this block of code, we started out by removing the global $dbi declaration and replaced it with $db. This gives us access to the $db abstraction layer object.

Next, we cleaned up the query a bit by using upper-case letters for all SQL language directives used in our query. This makes the query easy to read as it is very easy to differentiate between SQL STATEMENTS and variables.

We then converted the sql_query() call to $db-&amp;gt;sql_query(). Notice how we removed the $dbi as the second parameter to the query. This is important as DragonflyCMS™ uses additional parameters passed with the query for debugging purposes.

Now is where the fun begins.

The original loop around the call to sql_fetchrow() reads (in english) something like &quot;while you are getting a record from the database, please take the array returned by the sql_query call and use it to define these 4 variables: $com_id, $uname, $date, $comments.&quot;

SECURITY:
This works well in practice, however the more secure method of doing this is to always use &quot;$row = $db-&amp;gt;sql_fetchrow($result)&quot; as seen in the rewrite.

If, for some odd reason the query is able to be altered and alternate data is retrieved from the database, and attacker could easily use the list($variables) access method to retrieve information from your database and display it on the screen (or in the email, or whatever).

Next, you will see that we add our own variable assignments from the $row[] array that is returned by the call to $db-&amp;gt;sql_fetchrow(). Alternately, those lines could be removed and the echo statement could be changed to read:

PHP:
echo &quot;on &quot;.$row[&#039;date&#039;].&quot;,&quot;.$row[&#039;uname&#039;].&quot; left the comment &quot;.$row[&#039;comments&#039;].&quot;\n&quot;;


Either method is acceptable and is generally left up to the preference of the programmer.

Database Conclusion:
Now that we&#039;ve seen the two most common methods of database access converted to the abstraction layer, here is a table that shows various commands under the different methods and how they would look using the abstraction layer:

Code:

+----------------------------------------------------------------------------+
| MySQL API Method               | $db abstraction layer method              |
+----------------------------------------------------------------------------+
| mysql_query($sql)              | $db-&amp;gt;sql_query($sql)                      |
| mysql_fetch_array($res, TYPE)  | $db-&amp;gt;sql_fetchrow($res)                   |
| mysql_fetch_assoc($res)        | $db-&amp;gt;sql_fetchrow($res)                   |
| mysql_numrows($res)            | $db-&amp;gt;sql_numrows($res)                    |
| mysql_affected_rows($res)      | $db-&amp;gt;sql_affectedrows($res)               |
| mysql_num_fields($res)         | $db-&amp;gt;sql_numfields($res)                  |
| mysql_field_name($res, $index) | $db-&amp;gt;sql_fieldname($index, $res)          |
| mysql_field_type($res, $index) | $db-&amp;gt;sql_fieldtype($index, $res)          |
| mysql_fetch_rowset($res)       | $db-&amp;gt;sql_fetchrowset($res)                |
| mysql_fetch_field($res, $index)| $db-&amp;gt;sql_fetchfield($index, $rownum, $res)|
| mysql_data_seek($res, $rownum) | $db-&amp;gt;sql_rowseek($rownum, $res)           |
| mysql_insert_id($res)          | $db-&amp;gt;sql_nextid($res)                     |
| mysql_free_result($res)        | $db-&amp;gt;sql_freeresult($res)                 |
| mysql_error($res)              | $db-&amp;gt;sql_error($res)                      |
| mysql_connect()                | un-needed                                 |
| mysql_select_db()              | un-needed                                 |
+----------------------------------------------------------------------------+

+----------------------------------------------------------------------------+
| DBI Layer Method               | $db abstraction layer method              |
+----------------------------------------------------------------------------+
| sql_query($sql, $dbi)          | $db-&amp;gt;sql_fetchrow($sql)                   |
| sql_num_rows($res)             | $db-&amp;gt;sql_numrows($res)                    |
| sql_fetch_row($res)            | $db-&amp;gt;sql_fetchrow($res)                   |
| sql_fetch_array($res)          | $db-&amp;gt;sql_fetchrow($res)                   |
| sql_fetch_object($res)         | $db-&amp;gt;sql_fetchrow($res)                   |
| sql_free_result($res)          | $db-&amp;gt;sql_freeresult($res)                |
+----------------------------------------------------------------------------+

As you can see, the $db method not only offers better security and debugging features, it is also more flexible than the DBI sql layer.



Section 2: index.php, modules.php and admin.php vs getlink() and adminlink().

In CPG Dragonfly CMS™, the various entry points for your website are configurable via the $adminindex and $mainindex variables in config.php. Additionally, modules.php is no longer used.

DragonflyCMS™ accomplishes this via two functions: adminlink() and getlink().

When porting an application, you should convert all references to &quot;admin.php&quot;, &quot;index.php&quot;, and &quot;modules.php&quot; to their CPG Dragonfly CMS™ function equivalents.

getlink() is a function that returns the path to the main entry point of the website, usually &quot;index.php&quot;. And since all &quot;modules.php&quot; traffic is now routed through &quot;index.php&quot;, you use getlink() for that also.

adminlink() returns the path and filename to your administration menu, traditionally &quot;admin.php&quot;.

By converting links to their functional counterparts, you are ensuring that your newly ported module will work properly under all configurations.

These two link functions also accept additional arguments to be passed to the URL as a parameter.

Some examples of link conversions follow:

Code:
Before: echo &quot;&amp;lt;a href=\&quot;index.php\&quot;&amp;gt;Return&amp;lt;/a&amp;gt; to the main page.&amp;lt;br&amp;gt;&quot;;
After:  echo &quot;&amp;lt;a href=\&quot;&quot; . getlink() . \&quot;&amp;gt;Return&amp;lt;/a&amp;gt; to the main page.&amp;lt;br&amp;gt;&quot;;

Before: echo &quot;&amp;lt;a href=\&quot;admin.php\&quot;&amp;gt;Return&amp;lt;/a&amp;gt; to the admin section.&amp;lt;br /&amp;gt;&quot;;
After:  echo &quot;&amp;lt;a href=\&quot;&quot; . adminlink() . \&quot;&amp;gt;Return&amp;lt;/a&amp;gt; to the admin section.&amp;lt;br /&amp;gt;&quot;;

Before: echo &quot;&amp;lt;a href=\&quot;modules.php?name=Your_Account&amp;amp;op=userinfo\&quot;&amp;gt;Your Account&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;&quot;;
After:  echo &quot;&amp;lt;a href=\&quot;&quot;.getlink(&quot;Your_Account&amp;amp;amp;op=userinfo).&quot;\&quot;&amp;gt;Your Account&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;&quot;;

That last one requires a bit of explaining. As we noticed before, we used getlink() to direct the user at what is traditionally &quot;index.php&quot;. Here we used the same function for &quot;modules.php&quot;. Why? Because &quot;modules.php&quot; was removed from CPG Dragonfly CMS™ and all access passes though &quot;index.php&quot; now.

Additionally, you&#039;ll note that there is no &quot;name=&quot; added to the extra URL parameters. That is correct as getlink() figures out what you are doing and silently prepends the &quot;name=&quot; parameter to the URL.

Lastly, you&#039;ll notice that the &quot;&amp;amp;&quot; symbol was replaced with &quot;&amp;amp;a mp;&quot; (spaced so it won&#039;t parse). This is to ensure that your application creates HTML 4.01 Transitional compliant output.

How about a more complex example (mixed HTML and PHP code)?

Code:
Before:
&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;welcome to &amp;lt;?php echo $sitename; ?&amp;gt; &amp;lt;/head&amp;gt;&amp;lt;/title&amp;gt;
&amp;lt;a href=&quot;index.php&quot;&amp;gt;click here for them main page&amp;lt;/a&amp;gt;

After:
&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;welcome to &amp;lt;?php echo $sitename; ?&amp;gt; &amp;lt;/head&amp;gt;&amp;lt;/title&amp;gt;
&amp;lt;a href=&quot;&amp;lt;?php echo getlink(); ?&amp;gt;&quot;&amp;gt;click here for them main page&amp;lt;/a&amp;gt;

While it may not be proper HTML coding, it works. There is no reason not to use getlink() and adminlink() in your code!

Using getlink() and adminlink() instead of their hard-coded counterparts ensures that your port will continue to work as additional changes are made to the CPG Dragonfly CMS™ core system. These functions are located in &quot;linking.php&quot; in the CPG Dragonfly CMS™ /includes/functions/ folder.

Since CPG Dragonfly CMS™ gives you the option to use LEO (Link Engine Optimization), the use of getlink() and adminlink() will also properly convert your links to either method (LEO or non-LEO links), without having to think about whether or not you&#039;re using LEO. LEO converts URL&#039;s into search engine friendly link, using .html extensions, rather than .php. Examples of LEO and non-LEO links are below.

Code:
Standard link:
yoursite.tld/index.php?name=Forums

LEO link:
yoursite.tld/Forums.html




Section 3: How to Make a CPG Dragonfly CMS™ Auto-Installer

The modules section of the admin panel in CPG-Nuke has the option to automatically set up an installed module. This removes a lot of the frustration involved in installing a module and instead, turns it into a &quot;click to install&quot; process.

To accomplish this feature, CPG Dragonfly CMS™ uses an installation file called &quot;cpg_inst.php&quot; that is located in the modules&#039; main folder. For example: modules/MyApp/cpg_inst.php. A few things are necessary for Dragonfly to &quot;see&quot; this file. 1) an index.php file must also be present in the directory. 2) the directory for &quot;MyApp&quot; must be identical to the class/function in wording (see below for further explanation).

A trimmed down version of a cpg_inst.php file is this:

PHP:
######################################################
# File to install MyApp module
# This file is called automatically by Admin-&amp;gt;Modules
######################################################
if (!defined(&#039;ADMIN_MOD_INSTALL&#039;)) {  exit; }

class MyApp {
    var $radmin;
    var $version;
    var $modname;
    var $description;
    var $author;
    var $website;
    var $prefix;
    var $dbtables;

// class constructor
    function MyApp() {
        $this-&amp;gt;radmin = true;
        $this-&amp;gt;version = &#039;2.0.0.0&#039;;
        $this-&amp;gt;modname = &#039;MyApp&#039;;
        $this-&amp;gt;description = &#039;Use the MyApp Module (it was ported properly!)&#039;;
        $this-&amp;gt;author = &#039;AUTHOR_NAME&#039;;
        $this-&amp;gt;website = &#039;AUTHOR_SITE&#039;;
        $this-&amp;gt;prefix = strtolower(basename(dirname(__FILE__)));
        $this-&amp;gt;dbtables = array(&#039;myapp_data&#039;);
    }

// module installer
    function install() {
        global $installer;

        $installer-&amp;gt;add_query(&#039;CREATE&#039;, $this-&amp;gt;prefix.&#039;_myapp_data&#039;, &quot;
            pid int(10) NOT NULL auto_increment,
            title varchar(64) NOT NULL default &#039;0&#039;,
            PRIMARY KEY  (pid)&quot;, &#039;&#039;);

    $installer-&amp;gt;add_query(&#039;INSERT&#039;, $this-&amp;gt;prefix.&#039;_myapp_data&#039;, &#039;1, &quot;My Title&quot;&#039;);

        return true;
    }

// module uninstaller
    function uninstall() {
        global $installer;

        $installer-&amp;gt;add_query(&#039;DROP&#039;, $this-&amp;gt;prefix.&#039;_myapp_data&#039;);

}
?&amp;gt;

The cpg_inst.php is actually a class containing three things: A description of the module, an install function, and an uninstall function.

The $prefix is used to make it easier to have multiple instances of one module (if necessary). Your tablenames will have the module folder name (lowercase) as a prefix (e.g. &quot;cms_modulefoldername_table2&quot;).

The $description is used to identify your module on the modules administration panel before it is installed. And guess what? The install and uninstall function perform the needed steps to install and uninstall the module.

The $dbtables simply informs the backup system which tables are associated with this module.

One thing is *very* important in this file. You&#039;ll notice that there are two statements, &quot;class MyApp{}&quot; and &quot;function MyApp{}&quot;. Both of these statements should be changed to reflect your application&#039;s name. Also, remember that the directory name for your application should also be identical as well for Dragonfly to &quot;see&quot; the cpg_inst.php file.

Generally, the installation process for a module will include creating some database tables and seeding them with some basic data. Traditionally, this would be handled by an &quot;.sql&quot; file that the user would need to use to manually update their database tables. DragonflyCMS™ allows this to be handled by the install process in the cpg_inst.php file and reduce the number of problems associated with end users not knowing how to manually run a database query.





Section 4: File Locations, File Locations, and File Locations

In CPG Dragonfly CMS™, the directories are protected so that direct access to executable (.php) files is not allowed outside of certain directories. If you&#039;re porting a module, you should know that modules/ is one of those directories.

This basically means that at no point are you allowed to point a URL at the modules directory to run an application.

For example, the URL: localhost/modules/MyApp/print.php?id=12 is not allowed. The CPG Dragonfly CMS™ Security Module does not and will not allow for it. It&#039;s a security thing and you&#039;re just going to need to deal with it as best you can.

This is especially important as a feature of PHP-Nuke (not DragonflyCMS™!) is to include a file called &quot;copyright.php&quot; in each module&#039;s directory that will create a link on the modules&#039; page to a copyright notice. Remember that if you are porting a document, you must leave the existing copyrights in place!

In a pinch, you could simply add a link in the app you are porting to the URL listed above (http://.../modules.php?name=copyright) and you should be in good shape.

13.13.2: Part Two of Porting Applications

Section 5: Cookies and Users

It&#039;s common practice in PHP-Nuke modules to use the $cookie[] array to retrieve information about the currently logged in user. In DragonflyCMS™, this has been replaced with a very helpful variable: $userinfo[] (array).

$userinfo[] contains the information from the user&#039;s entry in the cms_users database table. In many PHP-Nuke apps, the $cookie[] variable is first decoded to get the user&#039;s name, then a database query is run to extract information from the database on that user. Relax. It&#039;s already taken care of with $userinfo[]. Any field in the _users table is available in the $userinfo[] array.

For Example:

PHP:
function getyourdetails()
{
    global $cookie;

    cookiedecode($user);
    $name = $cookie[1];

    $result = sql_query(&quot;select uid, name from &quot;.$user_prefix.&quot;_users where uname=&#039;$check&#039;&quot;, $dbi);
     list ($uid, $username) = sql_fetchrow($result, $dbi);
     echo &quot;Your nick is $name, your user id is $uid and your name is $username\n&quot;;
}

We would re-write that as follows:

PHP:
    global $userinfo; // needs to be declared global if inside a function.
    echo &quot;Your nick is &quot; . $userinfo[&#039;name&#039;] . &quot;, your user id is &quot; . $userinfo[&#039;user_id&#039;] . &quot;, and your name is &quot; . $userinfo[&#039;username&#039;] . &quot;\n&quot;;

That&#039;s correct. No cookie decoding, no database queries... You just use the data as it is supplied to you. Simple, huh?

There should be no need to touch the $user or $admin cookies in DragonflyCMS™ unless you ABSOLUTELY know what you are doing.





Section 6: Basic Security Precautions

One of CPG Dragonfly CMS™&#039;s major advantages over other CMS&#039;s is security. Since you will be inserting what is probably someone else&#039;s code into someone else&#039;s website, this should be high up on your priorities list also.

Some of the biggest avoidable security issues in CMS&#039;s today are:

* SQL Injection.
* Cross site scripting.
* Full path disclosure.
* Direct file access

SQL Injection
SQL Injection is relatively easy to avoid. You simply check all of your variables before inserting the into an SQL statement. To accomplish this, you simply need to know the type of data in the database fields and where that data is coming from in the application you are porting.

Imagine a table with two fields, &quot;pid&quot; and &quot;title&quot;. &quot;pid&quot; is a field of integer type, and &quot;title&quot; is of character type (char, varchar, text, etc...)

Now we have a simple piece of SQL query:

PHP:
function get_title($pid, $title)
{
    global $db;
    $sql = &quot;SELECT title &quot; .  
           &quot;FROM cms.MyApp_data &quot; .
           &quot;WHERE pid = $pid OR title=&#039;$title&#039;&quot;;

    $db-&amp;gt;sql_query($sql);
    $row = $db-&amp;gt;sql_fetchrow($result);
    return $row[&#039;title&#039;];
}


What do we do here? Well, we know that pid is an integer value, so we should make sure that it is. Or perhaps die trying. We also know that title is a character value, so we need to make sure that it has all of it&#039;s quotes (&quot; or &#039;) properly &quot;slashed&quot; before it goes into the query. CPG Dragonfly CMS™ has a nice function for the latter of the two called &quot;Fix_Quotes()&quot;.

When invoked with one parameter, Fix_Quotes() will check to see if the current PHP environment has the setting &quot;gpc_magic_quotes&quot; set to &quot;on.&quot; If it doesn&#039;t, it will &quot;slash&quot; the variable that it is passed for you. This is because when gpc_magic_quotes in &quot;on&quot;, PHP will automagically slash quotes in variables coming from HTTP_GET, HTTP_POST, and HTTP_COOKIE variables.

If you are *sure* that the variable is coming straight from a web page request into your query, you should run Fix_Quotes($variable); on that variable to assure proper quote handling. If you are unsure, or there is a possibility that the variable may be coming from several sources, you can always use the PHP function addslashes() and stripslashes().

We change the code to:

PHP:
function get_title($pid, $title)
{
   global $db;

   $pid = intval($pid); // assure that $pid is an integer.
//   if (!is_numeric($pid)) {
//      die (&quot;invalid pid parameter specified!&quot;);
//   }


   $title = Fix_Quotes($title);
// $title = addslashes(stripslashes($title)); // alternately, we could do this.

   $sql = &quot;SELECT title &quot;.
          &quot;FROM cms.MyApp_data &quot;.
          &quot;WHERE pid = $pid AND title = &#039;$title&#039;&quot;;

   $db-&amp;gt;sql_query($sql);
   $row = $db-&amp;gt;sql_fetchrow($result);
   return $title;
}


That&#039;s much better. We can either force $pid to be an integer with &quot;$pid = intval($pid);&quot; or check to see if it&#039;s an integer and scream bloody murder if it is not using the &quot;if (!is_numeric($pid)) {&quot; code.

For the character variables, we chose to use Fix_Quotes() on the $title variable since we&#039;re sure that by the time we see $title in the function, it hasn&#039;t been changed elsewhere in the program. If we weren&#039;t sure, or just completely paranoid, we could do the slash-twins on the variable, but that would add extra overhead to the program that Fix_Quotes() does not.



Cross-Site Scripting (XSS)

Cross Site Scripting, or XSS, is essentially finding ways to inject HTML, Javascript, or whatever code into someone else&#039;s web browser. It&#039;s as simple as that. The fix is nearly as simple.

In CPG Dragonfly CMS™, we have the function Fix_Quotes(). It actually accepts more than one parameter, the second of which is good for preventing XSS code from getting injected into your application.

Imagine this micro module, called &quot;Quote&quot;:

PHP:
&amp;lt;?php
// the never ending quote application
function addquote() {
    global $quote, $db;

    $db-&amp;gt;sql_query(&quot;INSERT INTO &quot;.$prefix.&quot;myquotes VALUES (0, &#039;$quote&#039;)&quot;);
    echo &quot;your quote is in the database, thanks!&amp;lt;br&amp;gt;&quot;;
}

function display_quote($id) {
    global $db;

    $id = intval($id);  // we&#039;re not THAT stupid.

    $db-&amp;gt;sql_query(&quot;SELECT quote FROM &quot;.$prefix.&quot;_myquotes WHERE id = $id&quot;);

    echo &quot;Your quote is &#039;&quot; . $quote . &quot;&#039;&amp;lt;br&amp;gt;&quot;;
    echo &quot;Click &amp;lt;a href=\&quot;&quot; . getlink(&#039;&amp;amp;id=&#039;.$id+1) . &quot;\&quot;&amp;gt;here&amp;lt;/a&amp;gt; for the next.\n&quot;;
}

switch ($op) {
    case &quot;display&quot;:
        display_quote($id);
        break;

    case &quot;add&quot;:
        add_quote();
        break;
};


In the quote_add() function, we are blindly adding the $quote variable both into an SQL query as well as the database itself. In the quote_display() function, we also simply toss the contents of the variable into the user&#039;s web browser. This is how XSS happens. To remedy this, we will use the Fix_Quotes() function again and change the add_quote() function to read:

PHP:
function addquote() {
    global $quote, $db;

    Fix_Quotes($quote, 1);

    $db-&amp;gt;sql_query(&quot;INSERT INTO &quot;.$prefix.:&quot;myquotes VALUES (0, &#039;$quote&#039;)&quot;);
    echo &quot;your quote is in the database, thanks!&amp;lt;br&amp;gt;&quot;;
}


By adding the second parameter &quot;1&quot; to Fix_Quotes(), we are telling Fix_Quotes() that not only would we like variable slashed, we would also like to strip any HTML or PHP code. Fix_Quotes() does this using the strip_tags() function of PHP.



Full Path Disclosure

Full path disclosure, by itself, is not a security issue. However, allowing someone with evil intent to figure out where certain files reside on your web server can be used in conjunction with other attacks to open large security holes.

Full path disclosure in PHP generally comes from warning errors. For example:

Code:
Warning: Division by zero in /home/www/html/tmp/foo.php on line 4

That would tell an attacker where on the server your web files are stored.

Since it is quite easy to turn of error reporting in the configuration of PHP, this won&#039;t be covered much here. Simply, when debugging your ported app, run it with the &quot;error_reporting(E_ALL);&quot; function call and browse over the errors (chances are, there will be many). Silence those that you can.

In the end, it is primarily the web developer&#039;s responsibility to make sure that error messages are not output to the users&#039; screen on a production site.


Direct File Access

The problem with direct file access is exactly as it sounds -- letting people run PHP code on your website without first passing through the front doors (index.php or admin.php).

In PHP-Nuke, this is generally accomplished with something similar to the following code at the top of each .php file:

PHP:
if (!eregi(&quot;modules.php&quot;, $_SERVER[&#039;PHP_SELF&#039;])) die(&quot;Access Denied&quot;);


What that says (in english) is &quot;if the current file being accessed when this chunk of PHP code is being run does not contain &#039;modules.php&#039;, then die.&quot;

In practice, that almost works well. But there are ways around this that we will not discuss here.

As a better security measure, DragonflyCMS™ defines some variables that may be checked to make sure that if a PHP file is getting executed, it&#039;s only being executed from within a proper section of the site, and definitely not being directly accessed.

For example, we would re-code the above code snippet as:

PHP:
if (!defined(&quot;CPG_NUKE&quot;)) { exit; }


You see, CPG_NUKE is defined() in includes/cmsinit.php. So... If your code is being executed and includes/cmsinit.php has not already been loaded, your code will halt execution.

There is also another nice variable that is define()d when the administrator is working from the admin panel. That is ADMIN_PAGES.

So... All of your adminstrator code should be protected like this:

PHP:
if (!defined(&quot;ADMIN_PAGES&quot;)) { exit; }


Administrator code is generally located in the admin/modules folder.

If the code you are porting is to be cross-ported (the same code running in DragonflyCMS™ as well as PHP-Nuke), this CAN be done without making your code DragonflyCMS™ specific. You would change the first piece of code to read like this:

PHP:
if (eregi(&quot;block-My_Block.php&quot;, $_SERVER[&#039;SCRIPT_NAME&#039;])) die(&quot;Access Denied&quot;);


Notice we&#039;re using SCRIPT_NAME instead of PHP_SELF. We are basically saying &quot;If the name of this file is in the full file/pathname of the script that is running, then die.&quot;

This method is much more risky as a simple typo renders it useless (block-My_Block.php vs. block-My_Bolck.php).

And just to &quot;toot&quot; DragonflyCMS&#039;s™ horn a bit, I should add that this is actually the second level of multi-tiered security against direct file access. On a properly installed and configured DragonflyCMS™ system, processing would never get this far.

Section 7: Register Globals - Importing Data


When on, register_globals will inject your scripts with all sorts of variables, like request variables from HTML forms. This coupled with the fact that PHP doesn&#039;t require variable initialization means writing insecure code is that much easier. CPG Dragonfly CMS™ runs with register_globals disabled.

When on, people use variables yet really don&#039;t know for sure where they come from and can only assume. Internal variables that are defined in the script itself get mixed up with request data sent by users and disabling register_globals changes this. Let&#039;s demonstrate with an example misuse of register_globals:

PHP:
&amp;lt;?php
// define $authorized = true only if user is authenticated
if (authenticated_user()) {
   $authorized = true;
}

// Because we didn&#039;t first initialize $authorized as false, this might be
// defined through register_globals, like from GET auth.php?authorized=1
// So, anyone can be seen as authenticated!
if ($authorized) {
   include &quot;/highly/sensitive/data.php&quot;;
}
?&amp;gt;

When register_globals = on, our logic above may be compromised. When off, $authorized can&#039;t be set via request so it&#039;ll be fine.

There is one caveat. By turning off register_globals, you can no longer access passed variables with their given name. They MUST be imported with either $_GET or $_POST, depending on where the data is coming from. $_GET is, generally, used with variables passed in links, while $_POST is used for variables coming from a posted form.

For example, say we are trying to get data passed from a simple form. The old, PHP-Nuke way is to simply access the variables by their given name.

PHP:
    // update the database with posted variables
    global $dbi, $prefix;

    $sql = &quot;INSERT INTO &quot;.$prefix.&quot;_mytable SET myphone=&#039;&quot;.$myphone.&quot;&#039;, myaddress=&#039;&quot;.$myaddress.&quot;&#039;, mybirthdate=&#039;&quot;.$mybirthdate.&quot;&#039;&quot;;
    $result = sql_query($sql, $dbi);

With CPG Dragonfly CMS™ you must import these variables prior to using them, for reasons discussed above. We would rewrite the above as;

PHP:
    // update the database with posted variables
    global $db, $prefix;

    $myphone = Fix_Quotes($_POST[&#039;myphone&#039;], 1);
    $myaddress = Fix_Quotes($_POST[&#039;myaddress&#039;], 1);
    $mybirthdate = Fix_Quotes($_POST[&#039;mybirthdate&#039;], 1);

    $sql = &quot;INSERT INTO &quot;.$prefix.&quot;_mytable SET myphone=&#039;&quot;.$myphone.&quot;&#039;, myaddress=&#039;&quot;.$myaddress.&quot;&#039;, mybirthdate=&#039;&quot;.$mybirthdate.&quot;&#039;&quot;;
    $result = $db-&amp;gt;sql_query($sql);
    $db-&amp;gt;sql_freeresult($sql);

Alternatively, you could re-write it like this, also mentioned above;

PHP:
    // update the database with posted variables
    global $db, $prefix;

    $sql = &quot;INSERT INTO &quot;.$prefix.&quot;_mytable SET myphone=&#039;&quot;.Fix_Quotes($_POST[&#039;myphone&#039;], 1).&quot;&#039;, myaddress=&#039;&quot;.Fix_Quotes($_POST[&#039;myaddress&#039;
], 1).&quot;&#039;, mybirthdate=&#039;&quot;.Fix_Quotes($_POST[&#039;mybirthdate&#039;], 1).&quot;&#039;&quot;;
    $result = $db-&amp;gt;sql_query($sql);
    $db-&amp;gt;sql_freeresult($sql);

The first method, in my opinion, is simply easier to read and work with. It is also easier to check whether these variables are set, before trying to assign them to another variable. For example, the routine could again be rewritten as;

PHP:
    // update the database with posted variables
    global $db, $prefix;

    $myphone = isset($_POST[&#039;myphone&#039;]) ? Fix_Quotes($_POST[&#039;myphone&#039;], 1) : &#039;&#039;;
    $myaddress = isset($_POST[&#039;myaddress&#039;]) ? Fix_Quotes($_POST[&#039;myaddress&#039;], 1) : &#039;&#039;;
    $mybirthdate = isset($_POST[&#039;mybirthdate&#039;]) ? Fix_Quotes($_POST[&#039;mybirthdate&#039;], 1) : &#039;&#039;;

    $sql = &quot;INSERT INTO &quot;.$prefix.&quot;_mytable SET myphone=&#039;&quot;.$myphone.&quot;&#039;, myaddress=&#039;&quot;.$myaddress.&quot;&#039;, mybirthdate=&#039;&quot;.$mybirthdate.&quot;&#039;&quot;;
    $result = $db-&amp;gt;sql_query($sql);
    $db-&amp;gt;sql_freeresult($sql);

Basically, what this is saying (in English) is -- if the variable $_POST[&#039;myphone&#039;] is set (contains data) THEN Fix_Quotes on the data in $_POST[&#039;myphone&#039;] (and strip_tags) and assign it to $myphone, ELSE set $myphone to nothing (NULL).

This also holds true to switches used within many modules. For example;

PHP:
switch($mode) {
    case &quot;something&quot;:
        something ();
        break;

    case &quot;somethingelse&quot;:
        somethingelse ();
        break;
}

With this code, $mode is never set, hence no function is called. The proper way would be;

PHP:
$mode = isset($_POST[&#039;mode&#039;]) ? $_POST[&#039;mode&#039;] : &#039;something&#039;;
switch($mode) {
    case &quot;something&quot;:
        something ();
        break;

    case &quot;somethingelse&quot;:
        somethingelse ();
        break;
}

This is assuming that you have data being passed from a posted form. If you have a switch that will be used with both $_GET and $_POST, you could use the following;

PHP:
$mode = isset($_POST[&#039;mode&#039;]) ? $_POST[&#039;mode&#039;] : (isset($_GET[&#039;mode&#039;]) ? $_GET[&#039;mode&#039;] : &#039;something&#039;);
switch($mode) {
    case &quot;something&quot;:
        something ();
        break;

    case &quot;somethingelse&quot;:
        somethingelse ();
        break;
}

There are many ways to do this, above is just one example. Notice that I have chosen a default routine to run, if $mode is not set. You could also set a default case to run and set mode to empty if it is not set.

PHP:
$mode = isset($_POST[&#039;mode&#039;]) ? $_POST[&#039;mode&#039;] : (isset($_GET[&#039;mode&#039;]) ? $_GET[&#039;mode&#039;] : &#039;&#039;);
switch($mode) {
   default:
    case &quot;something&quot;:
        something ();
        break;

    case &quot;somethingelse&quot;:
        somethingelse ();
        break;
}



References:
Functions / special variables mentioned in this document and their source code/documentation:

$userinfo[] - includes/cmsinit.inc
getlink() - includes/functions/linking.php
adminlink() - includes/functions/linking.php
Fix_Quotes() - includes/cmsinit.inc
addslashes() - www.php.net/manual/en/...lashes.php
stripslashes() - www.php.net/manual/en/...lashes.php
strip_tags() - www.php.net/manual/en/...p-tags.php
 	Author: tuta
Created: Saturday, November 05, 2005 (19:52:58)
Last update: Thursday, November 17, 2005 (15:40:17) by tuta</description>
  <pubDate>Mon, 28 Jun 2010 22:26:45 GMT</pubDate>
  <guid>http://dfaddons.com/ForumsPro/viewtopic/p=88.html#88</guid>
</item></channel>
</rss>