p2p.wrox.com Forums

Need to download code?

View our list of code downloads.


  Return to Index  

beginning_php thread: function included by called "undefined"


Message #1 by spam@k... on Sat, 14 Sep 2002 13:51:29 -0500
I don't know if anyone can help me on this one, but maybe you can give me ideas for where to look for
what this problem might be. I wrote a simple content management system. A user can add and edit pages from a page called
"controlPanel.php". The functions that make it work are in other files, which are all included. Everything was working until 60
minutes ago when I moved some of the functions into files with names that more exactly represented what they did. Now I'm getting
this: 


Fatal error: Call to undefined function: printtemplatesection() in
/usr/local/plesk/apache/vhosts/alternativestopaving.monkeyclaus.org/httpdocs/mcIncludes/mcBaseFunctions.php on line 455

This is top part of the controlPanel, where the other files are included: 

include("mcConfig.php");
include("mcBaseFunctions.php");
include("mcNavFunctions.php");
include("mcArticleFunctions.php");
include("mcCatPageFunctions.php");
include("mcEmailFunctions.php");
include("mcQuoteFunctions.php");
include("mcStyleSheetFunctions.php");
include("mcUploadDownloadFunctions.php");
//include("mcUserSystem.php");
include("mcTemplateFunctions.php");
include("mcCommentsFunctions.php");
include("mcInstallScript.php");


There is a function in mcTemplateFunctions.php that is being called from mcBaseFunctions. 


Here are some of the things that I've done so far to try to figure out this problem:

1. Double check name of function. Copy it from where it is declared and paste it into where its being called, just to catch any
spelling errors that my eye was missing. 

2. Check for unclosed C-style comment marks, like /*, which might have enclosed the definition of the function. 

3. Cut the functions from mcBaseFunctions.php and paste them into a file called wrap.php, and make wrap.php the last declared in
Control panel, so that these functions would be included, and make their calls, only after mcTemplateFunctions were already
included. 

None of this has worked. Other ideas? 


take care,

lawrence 


Message #2 by spam@k... on Sat, 14 Sep 2002 14:07:04 -0500
Oh wait, the situation is much weirder than I thought. I can get to the controlPanel. But then when I
choose an option, like to modify the CatPageQuotes (links on category pages that link to articles) then I get "undefined function"
error. And yet, I am on the same page, controlPanel.php, and it had to use the supposedly "undefined" function when I first arrived
at the screen. But the error only shows up when once I choose an option. 

(One other thing I checked was to make sure the included files are all wrapped in<?php ?> tags. )


------------------------------------------------
On Sat, 14 Sep 2002 13:51:29 -0500, spam@k... wrote:

> I don't know if anyone can help me on this one, but maybe you can give me ideas for where to look for what this problem might
be. I wrote a simple content management system. A user can add and edit pages from a page called "controlPanel.php". The functions
that make it work are in other files, which are all included. Everything was working until 60 minutes ago when I moved some of the
functions into files with names that more exactly represented what they did. Now I'm getting this: 
> 
> 
> Fatal error: Call to undefined function: printtemplatesection() in
/usr/local/plesk/apache/vhosts/alternativestopaving.monkeyclaus.org/httpdocs/mcIncludes/mcBaseFunctions.php on line 455
> 
> This is top part of the controlPanel, where the other files are included: 
> 
> include("mcConfig.php");
> include("mcBaseFunctions.php");
> include("mcNavFunctions.php");
> include("mcArticleFunctions.php");
> include("mcCatPageFunctions.php");
> include("mcEmailFunctions.php");
> include("mcQuoteFunctions.php");
> include("mcStyleSheetFunctions.php");
> include("mcUploadDownloadFunctions.php");
> //include("mcUserSystem.php");
> include("mcTemplateFunctions.php");
> include("mcCommentsFunctions.php");
> include("mcInstallScript.php");
> 
> 
> There is a function in mcTemplateFunctions.php that is being called from mcBaseFunctions. 
> 
> 
> Here are some of the things that I've done so far to try to figure out this problem:
> 
> 1. Double check name of function. Copy it from where it is declared and paste it into where its being called, just to catch any
spelling errors that my eye was missing. 
> 
> 2. Check for unclosed C-style comment marks, like /*, which might have enclosed the definition of the function. 
> 
> 3. Cut the functions from mcBaseFunctions.php and paste them into a file called wrap.php, and make wrap.php the last declared
in Control panel, so that these functions would be included, and make their calls, only after mcTemplateFunctions were already
included. 
> 
> None of this has worked. Other ideas? 
> 
> 
> take care,
> 
> lawrence 
> 
> 
> 
> 
Message #3 by spam@k... on Sat, 14 Sep 2002 14:16:54 -0500
I wrote a simple content management system, and until today the thing was run by a giant switch
statement on the main page. A single variable called $choiceMade decided which function was called. Last night, in a fit unworkable
genius, I decided to break up that one big switch statement. Now all the functions are called from the revlevant file. For instance,
any of the functions that have to do with articles are called from a switch statement in mcArticleFunctions.php. 

This seems to be where my trouble is coming from, though I haven't figured it out yet. The default screen is defined in a function
which is in mcBaseFunctions.php and it continues to work. But most of the further screens are not working. They complain they are
getting an undefined function. 




switch ($choiceMade){

	case "printAddEdDelQuoteForm":
	printAddEdDelQuoteForm();
	break;

	case "addQuoteForm1":
	addQuoteForm1();
	break;

	case "addQuoteForm2":
	addQuoteForm2();
	break;

	case "putQuoteInDb":
	putQuoteInDb();
	break;

	case "editQuoteForm1":
	editQuoteForm1();
	break;

	case "editQuoteForm2":
	editQuoteForm2();
	break;

	case "updateQuoteInDb":
	updateQuoteInDb();
	break;

	case "deleteQuoteForm":
	deleteQuoteForm();
	break;

	case "deleteQuoteFromDb":
	deleteQuoteFromDb();
	break;

}













------------------------------------------------
On Sat, 14 Sep 2002 14:07:04 -0500, spam@k... wrote:

> Oh wait, the situation is much weirder than I thought. I can get to the controlPanel. But then when I choose an option, like to
modify the CatPageQuotes (links on category pages that link to articles) then I get "undefined function" error. And yet, I am on the
same page, controlPanel.php, and it had to use the supposedly "undefined" function when I first arrived at the screen. But the error
only shows up when once I choose an option. 
> 
> (One other thing I checked was to make sure the included files are all wrapped in<?php ?> tags. )
> 
> 
> ------------------------------------------------
> On Sat, 14 Sep 2002 13:51:29 -0500, spam@k... wrote:
> 
> > I don't know if anyone can help me on this one, but maybe you can give me ideas for where to look for what this problem
might be. I wrote a simple content management system. A user can add and edit pages from a page called "controlPanel.php". The
functions that make it work are in other files, which are all included. Everything was working until 60 minutes ago when I moved
some of the functions into files with names that more exactly represented what they did. Now I'm getting this: 
> > 
> > 
> > Fatal error: Call to undefined function: printtemplatesection() in
/usr/local/plesk/apache/vhosts/alternativestopaving.monkeyclaus.org/httpdocs/mcIncludes/mcBaseFunctions.php on line 455
> > 
> > This is top part of the controlPanel, where the other files are included: 
> > 
> > include("mcConfig.php");
> > include("mcBaseFunctions.php");
> > include("mcNavFunctions.php");
> > include("mcArticleFunctions.php");
> > include("mcCatPageFunctions.php");
> > include("mcEmailFunctions.php");
> > include("mcQuoteFunctions.php");
> > include("mcStyleSheetFunctions.php");
> > include("mcUploadDownloadFunctions.php");
> > //include("mcUserSystem.php");
> > include("mcTemplateFunctions.php");
> > include("mcCommentsFunctions.php");
> > include("mcInstallScript.php");
> > 
> > 
> > There is a function in mcTemplateFunctions.php that is being called from mcBaseFunctions. 
> > 
> > 
> > Here are some of the things that I've done so far to try to figure out this problem:
> > 
> > 1. Double check name of function. Copy it from where it is declared and paste it into where its being called, just to
catch any spelling errors that my eye was missing. 
> > 
> > 2. Check for unclosed C-style comment marks, like /*, which might have enclosed the definition of the function. 
> > 
> > 3. Cut the functions from mcBaseFunctions.php and paste them into a file called wrap.php, and make wrap.php the last
declared in Control panel, so that these functions would be included, and make their calls, only after mcTemplateFunctions were
already included. 
> > 
> > None of this has worked. Other ideas? 
> > 
> > 
> > take care,
> > 
> > lawrence 
> > 
> > 
> > 
> > 
> 
> 
Message #4 by spam@k... on Sat, 14 Sep 2002 14:19:35 -0500
Oh, never mind. I'm being stupid. Putting the switch statements in each file means functions are being
called before everything has a chance to load. Yet another brilliant design idea shot down. Can you tell I didn't major in computer
science? I suppose if I had then I would have seen this as an obivious design mistake. Then again, those books by Robert Glass about
software projects gone bad make me think even the big companies can be stupid. Anyone want to do a computer system for the FAA? 




------------------------------------------------
On Sat, 14 Sep 2002 14:07:04 -0500, spam@k... wrote:

> Oh wait, the situation is much weirder than I thought. I can get to the controlPanel. But then when I choose an option, like to
modify the CatPageQuotes (links on category pages that link to articles) then I get "undefined function" error. And yet, I am on the
same page, controlPanel.php, and it had to use the supposedly "undefined" function when I first arrived at the screen. But the error
only shows up when once I choose an option. 
> 
> (One other thing I checked was to make sure the included files are all wrapped in<?php ?> tags. )
> 
> 
> ------------------------------------------------
> On Sat, 14 Sep 2002 13:51:29 -0500, spam@k... wrote:
> 
> > I don't know if anyone can help me on this one, but maybe you can give me ideas for where to look for what this problem
might be. I wrote a simple content management system. A user can add and edit pages from a page called "controlPanel.php". The
functions that make it work are in other files, which are all included. Everything was working until 60 minutes ago when I moved
some of the functions into files with names that more exactly represented what they did. Now I'm getting this: 
> > 
> > 
> > Fatal error: Call to undefined function: printtemplatesection() in
/usr/local/plesk/apache/vhosts/alternativestopaving.monkeyclaus.org/httpdocs/mcIncludes/mcBaseFunctions.php on line 455
> > 
> > This is top part of the controlPanel, where the other files are included: 
> > 
> > include("mcConfig.php");
> > include("mcBaseFunctions.php");
> > include("mcNavFunctions.php");
> > include("mcArticleFunctions.php");
> > include("mcCatPageFunctions.php");
> > include("mcEmailFunctions.php");
> > include("mcQuoteFunctions.php");
> > include("mcStyleSheetFunctions.php");
> > include("mcUploadDownloadFunctions.php");
> > //include("mcUserSystem.php");
> > include("mcTemplateFunctions.php");
> > include("mcCommentsFunctions.php");
> > include("mcInstallScript.php");
> > 
> > 
> > There is a function in mcTemplateFunctions.php that is being called from mcBaseFunctions. 
> > 
> > 
> > Here are some of the things that I've done so far to try to figure out this problem:
> > 
> > 1. Double check name of function. Copy it from where it is declared and paste it into where its being called, just to
catch any spelling errors that my eye was missing. 
> > 
> > 2. Check for unclosed C-style comment marks, like /*, which might have enclosed the definition of the function. 
> > 
> > 3. Cut the functions from mcBaseFunctions.php and paste them into a file called wrap.php, and make wrap.php the last
declared in Control panel, so that these functions would be included, and make their calls, only after mcTemplateFunctions were
already included. 
> > 
> > None of this has worked. Other ideas? 
> > 
> > 
> > take care,
> > 
> > lawrence 
> > 
> > 
> > 
> > 
> 
> 
Message #5 by spam@k... on Sat, 14 Sep 2002 14:28:33 -0500
What are good approaches for making large pieces of software modular? I'm looking for articles that
address this design idea with PHP in mind. 

I broke up the switch statement that ran my software because I wanted each file to be a self enclosed program. I wanted
mcArticleFunctions.php to be a self enclosed program, with all the forms and functions it needed to run, and switch statement to
call those functions. And I wanted mcCommentFunctions to also be its own piece of software. I've got 150k of code, and it's getting
large enough that it needs to be broken up some. 

But it seems I need to keep the switch statement on one page. 

But does anyone know of a good example of modular design using PHP, or an article about it? 






------------------------------------------------
On Sat, 14 Sep 2002 14:19:35 -0500, spam@k... wrote:

> Oh, never mind. I'm being stupid. Putting the switch statements in each file means functions are being called before everything
has a chance to load. Yet another brilliant design idea shot down. Can you tell I didn't major in computer science? I suppose if I
had then I would have seen this as an obivious design mistake. Then again, those books by Robert Glass about software projects gone
bad make me think even the big companies can be stupid. Anyone want to do a computer system for the FAA? 
> 
> 
> 
> 
> ------------------------------------------------
> On Sat, 14 Sep 2002 14:07:04 -0500, spam@k... wrote:
> 
> > Oh wait, the situation is much weirder than I thought. I can get to the controlPanel. But then when I choose an option,
like to modify the CatPageQuotes (links on category pages that link to articles) then I get "undefined function" error. And yet, I
am on the same page, controlPanel.php, and it had to use the supposedly "undefined" function when I first arrived at the screen. But
the error only shows up when once I choose an option. 
> > 
> > (One other thing I checked was to make sure the included files are all wrapped in<?php ?> tags. )
> > 
> > 
> > ------------------------------------------------
> > On Sat, 14 Sep 2002 13:51:29 -0500, spam@k... wrote:
> > 
> > > I don't know if anyone can help me on this one, but maybe you can give me ideas for where to look for what this
problem might be. I wrote a simple content management system. A user can add and edit pages from a page called "controlPanel.php".
The functions that make it work are in other files, which are all included. Everything was working until 60 minutes ago when I moved
some of the functions into files with names that more exactly represented what they did. Now I'm getting this: 
> > > 
> > > 
> > > Fatal error: Call to undefined function: printtemplatesection() in
/usr/local/plesk/apache/vhosts/alternativestopaving.monkeyclaus.org/httpdocs/mcIncludes/mcBaseFunctions.php on line 455
> > > 
> > > This is top part of the controlPanel, where the other files are included: 
> > > 
> > > include("mcConfig.php");
> > > include("mcBaseFunctions.php");
> > > include("mcNavFunctions.php");
> > > include("mcArticleFunctions.php");
> > > include("mcCatPageFunctions.php");
> > > include("mcEmailFunctions.php");
> > > include("mcQuoteFunctions.php");
> > > include("mcStyleSheetFunctions.php");
> > > include("mcUploadDownloadFunctions.php");
> > > //include("mcUserSystem.php");
> > > include("mcTemplateFunctions.php");
> > > include("mcCommentsFunctions.php");
> > > include("mcInstallScript.php");
> > > 
> > > 
> > > There is a function in mcTemplateFunctions.php that is being called from mcBaseFunctions. 
> > > 
> > > 
> > > Here are some of the things that I've done so far to try to figure out this problem:
> > > 
> > > 1. Double check name of function. Copy it from where it is declared and paste it into where its being called, just to
catch any spelling errors that my eye was missing. 
> > > 
> > > 2. Check for unclosed C-style comment marks, like /*, which might have enclosed the definition of the function. 
> > > 
> > > 3. Cut the functions from mcBaseFunctions.php and paste them into a file called wrap.php, and make wrap.php the last
declared in Control panel, so that these functions would be included, and make their calls, only after mcTemplateFunctions were
already included. 
> > > 
> > > None of this has worked. Other ideas? 
> > > 
> > > 
> > > take care,
> > > 
> > > lawrence 
> > > 
> > > 
> > > 
> > > 
> > 
> > 
> 
> 
Message #6 by "Nikolai Devereaux" <yomama@u...> on Mon, 16 Sep 2002 11:19:18 -0700
Augh!  If only I had more time!!  This is the kind of book that I'd like to
write...

Here's a couple tips, though.

Don't think that each file should be a working program.  Each file should
contain either a class definition or related utility function definitions.

Each function should use generic database methods.

Don't ever mix the HTML and SQL.

use require_once() to include all files that don't execute any code (that
is, they just provide function/class definitions).

The execution of any page should (for the most part) all be in one file.
This file will include (require_once) any files necessary for it to run.


Take care,

Nik

Message #7 by spam@k... on Mon, 16 Sep 2002 18:11:45 -0500
> Each function should use generic database methods.

But some functions have to make very specific queries of the datbase? If you'd said, "Keep all your queries in a separate file", I
would have understood. I remember earlier this year you wrote about how you keep all your calls stored on their own, in a manner
that mimiced stored procedures. But I don't have enough of a computer science background to understand what "generic" database
method means in this case. 


 
> Don't ever mix the HTML and SQL.

If I understand you right, you're saying don't ever make a query, get the result, and output the result mixed with HTML, all in one
function? 



PS. Google seems to do a poor job of watching Wrox, since when I search for your name this site rarely comes up. However, you do
seem to be all over the place, elsewhere, working with Smarty, then xml-java, then suggesting features like wc on the PHP Dev list.
You must work all the time. Do you ever sleep? 
Message #8 by "Nikolai Devereaux" <yomama@u...> on Mon, 16 Sep 2002 16:51:45 -0700
> > Each function should use generic database methods.
>
> But some functions have to make very specific queries of the
> datbase? If you'd said, "Keep all your queries in a separate
> file", I would have understood. I remember earlier this year you
> wrote about how you keep all your calls stored on their own, in a
> manner that mimiced stored procedures. But I don't have enough of
> a computer science background to understand what "generic"
> database method means in this case.

What I mean by this is that you should use some generic DB function
wrappers.  Take a look at the PEAR db abstraction classes.

The gist of what I mean is that you will make function calls like db_query()
and db_error() instead of mysql_query or pgsql_error().

This will make your script much more portable should you decide to switch
databases later on.

This might seem like a frivolous waste of time, but trust me -- once you
start developing more complicated applications, you'll run into MySQL's
limitations pretty quickly.  By depending on mysql throughout your script,
you're basically saying that you hope mysql becomes more feature rich as
your applications do.


> > Don't ever mix the HTML and SQL.
>
> If I understand you right, you're saying don't ever make a query,
> get the result, and output the result mixed with HTML, all in one
> function?

Right right.  Instead of this:

$query = "SELECT username, first_name FROM users WHERE id='$userid'";
$res = mysql_query($query);
if($res)
{
   $row = mysql_fetch_array($res);
   echo "<B>Hello, $row[first_name]!</B>";
}




You'll have this:

-- db.mysql.inc.php --
<?php
// db.mysql.inc.php
// This file defines generic functions which wrap mysql functions.

function db_query($query)
{
  return mysql_query($query);
}

function db_error()
{
  return mysql_error();
}

// etc...
?>
----------------


-- db.pgsql.inc.php --
<?php
// db.pgsql.inc.php
// This file defines generic functions which wrap
// postgresql functions.

function db_query($query)
{
  return pgsql_query($query);
}

function db_error()
{
  return pgsql_error();
}

// etc...
?>
----------------

-- db.inc.php --
<?php
// db.inc.php
// This file contains all the generic wrapper functions
// to be used by any PHP application.

switch($RDBMS)
{
   case 'mysql':
      require_once('db.mysql.inc.php');
      break;
   case 'pgsql':
      require_once('db.pgsql.inc.php');
      break;
   default:
      exit('Invalid RDBMS Defined: $RDBMS');
      break;
}
---------------


-- In user.inc.php --
<?php
// user.inc.php
// This file contains all the functions required for a program
// to interface with the user data.  The main script should not
// know or care whether the user information is stored in a
// database, flat files, or is hard coded.

require_once('db.inc.php'); // for generic db wrapper definitions

function get_user_info($userid)
{
   $query = "SELECT username, first_name
               FROM users WHERE id='$userid'";
   $res = db_query($query); // notice the generic wrapper

   $info = array();

   if($res)
   {
      $info = db_fetch_array($res, DB_ASSOC);
   }

   return $info;
}

?>
----------------


-- config.inc.php --
<?php
// config.inc.php
// This file contains site specific configuration settings.

$RDBMS   = 'mysql';
$DB_USER = 'username';
$DB_PASS = 'password';
$DB_HOST = 'localhost';


$DEBUG_MODE = false;

$BASE_PATH = '/home/nikolai/public_html/bigaction.org/';
$BASE_URL = '/';

require_once('db.inc.php');
require_once('user.inc.php');
?>
----------------

-- bigaction.inc.php --
<?php
// bigaction.inc.php
// This file defines functions which generate HTML for
// bigaction.org.

require_once('user.inc.php');

function page_header($title)
{
  $hdr = <<<EOH
<HTML>
<HEAD>
  <LINK rel="stylesheet" type="text/css" href="bigaction.css" />
  <TITLE>$title</TITLE>
</HEAD>
<BODY>
EOH;

  return $hdr;
}

function user_greeting($userid)
{
  $info = get_user_info($userid);

  return "<span class=\"greeting\">Hello, "
        . $info['first_name'] . "</span>\n";
}
----------------

-- main.php --
<?php
// main.php
// This file is where all the script execution logic is located.

require_once('config.inc.php');

require_once('bigaction.inc.php');

echo user_greeting($userid);

?>
----------------


It's a lot of work, but the benefit lies in that you can write a lot of
utility code ONCE, and then use it again and again for every site you do
after.  It dramatically increases your productivity.  Plus, it increases the
stability of your site, since you've already written and tested all your
utility code, so there's that much less that can cause problems later on.

Hope this helps,

nik



> PS. Google seems to do a poor job of watching Wrox, since when I
> search for your name this site rarely comes up. However, you do
> seem to be all over the place, elsewhere, working with Smarty,
> then xml-java, then suggesting features like wc on the PHP Dev
> list. You must work all the time. Do you ever sleep?

I sleep... sometimes too much, but it never feels like enough. =)  I don't
actually do any PHP programming for work right now -- I've been immersed in
the C++ world for a while.  If I had the time, I'd create a new
bigaction.org site and post a lot of PHP tips/tricks/faqs, etc...  Sad thing
is that there's nothing I can really do that hasn't already been done.  One
of my main reasons for NOT creating a personal home page with programming
language specific topics is because I'd really prefer to have one great
central site for good content to be located.  It wouldn't be helpful to you,
as a new programmer, to have to look at phpbuilder for one thing, php.net
for another, burhan's site for something else, and my site for yet another
thing.

Besides, I've got a girlfriend who's MUCH more rewarding to be with than my
'puter. =D


take care,

nik

Message #9 by spam@k... on Mon, 16 Sep 2002 23:03:12 -0500
Following up on this subject, are there any hard and fast rules about when to take a block of code out
of one function and make it into its own function? I'm thinking about this tonight as I write my code. At one point a few months ago
I thought that any 3 lines that repeated somewhere were candidates for becoming functions, but I found that actually turning them
into functions turned my code into spagetti - I ended up with a lot of small functions that I could barely remember I was supposed
to use. And then later I ended up undoing a lot of that work and moving toward larger functions - I'd rather have some repeating
code then an endless string of functions calling functions calling functions. I know there must be some level of functions calling
functions that is fundamentally unhealthy, but my sense for software design is too weak for me to understand what that level might
be. 

In the function below, the actual call to the database is done with a function called getNavFromDb(). In this function below the
writing of the urls could probably be handled by a more generic function. I've got a bunch of functions throughout my code that in
the course of their work cobble together urls. But every function I write that is called by another function is that much more
spagetti. I've got functions that call functions that call functions, and as you pointed out a few months ago, looking at one of my
other functions, I was sometimes including the config.php file 3 times, as each function called inside another function was quite
indpendently including the config. This is still a problem with my code, though I'm not sure what the right answer is. For instance,
again looking at the function below, I've a function called connectMcToDb() that is called inside of getNavFromDb(). Is that the
appropriate place for it to be called? 



function showNav($section = 1) {
	global $PHP_SELF;
	$self = $PHP_SELF;
	// This function runs getNavFromDb and gets back a 2 dimensional array that holds 
	//  navId, navLinkText, navSection, navOOA, navLinksToNumber, navLinksToType from mcNavigation in each row.
	$nav = getNavFromDb($section);
	echo "<div class='dvclLinksBlock'>";

	for ($i=0; $i < count($nav); $i++) {
		if ($nav[$i][2] == $section) {
			$navLinksToType = $nav[$i][5];

			if ($navLinksToType == "article") {
				$url = "<a href='";
				$url .= $self;
				$url .= "?articleId=";
				$url .= $nav[$i][4];
				$url .= "'>";
				$url .= $nav[$i][1];
				$url .= "</a><br>";
				echo $url;
			}

			if ($navLinksToType == "catPage") {
				$url = "<a href='";
				$url .= $self;
				$url .= "?catPageId=";
				$url .= $nav[$i][4];
				$url .= "'>";
				$url .= $nav[$i][1];
				$url .= "</a><br>";
				echo $url;
			}

			if ($navLinksToType == "builtInPage") {
				$url = "<a href='";
				$url .= $self;
				$url .= "?builtInPage=";
				$url .= $nav[$i][4];
				$url .= "'>";
				$url .= $nav[$i][1];
				$url .= "</a><br>";
				echo $url;
			}

		}
	}

	echo "</div>";
}










------------------------------------------------
On Mon, 16 Sep 2002 16:51:45 -0700, "Nikolai Devereaux" <yomama@u...> wrote:

> 
> > > Each function should use generic database methods.
> >
> > But some functions have to make very specific queries of the
> > datbase? If you'd said, "Keep all your queries in a separate
> > file", I would have understood. I remember earlier this year you
> > wrote about how you keep all your calls stored on their own, in a
> > manner that mimiced stored procedures. But I don't have enough of
> > a computer science background to understand what "generic"
> > database method means in this case.
> 
> What I mean by this is that you should use some generic DB function
> wrappers.  Take a look at the PEAR db abstraction classes.
> 
> The gist of what I mean is that you will make function calls like db_query()
> and db_error() instead of mysql_query or pgsql_error().
> 
> This will make your script much more portable should you decide to switch
> databases later on.
> 
> This might seem like a frivolous waste of time, but trust me -- once you
> start developing more complicated applications, you'll run into MySQL's
> limitations pretty quickly.  By depending on mysql throughout your script,
> you're basically saying that you hope mysql becomes more feature rich as
> your applications do.
> 
> 
> > > Don't ever mix the HTML and SQL.
> >
> > If I understand you right, you're saying don't ever make a query,
> > get the result, and output the result mixed with HTML, all in one
> > function?
> 
> Right right.  Instead of this:
> 
> $query = "SELECT username, first_name FROM users WHERE id='$userid'";
> $res = mysql_query($query);
> if($res)
> {
>    $row = mysql_fetch_array($res);
>    echo "<B>Hello, $row[first_name]!</B>";
> }
> 
> 
> 
> 
> You'll have this:
> 
> -- db.mysql.inc.php --
> <?php
> // db.mysql.inc.php
> // This file defines generic functions which wrap mysql functions.
> 
> function db_query($query)
> {
>   return mysql_query($query);
> }
> 
> function db_error()
> {
>   return mysql_error();
> }
> 
> // etc...
> ?>
> ----------------
> 
> 
> -- db.pgsql.inc.php --
> <?php
> // db.pgsql.inc.php
> // This file defines generic functions which wrap
> // postgresql functions.
> 
> function db_query($query)
> {
>   return pgsql_query($query);
> }
> 
> function db_error()
> {
>   return pgsql_error();
> }
> 
> // etc...
> ?>
> ----------------
> 
> -- db.inc.php --
> <?php
> // db.inc.php
> // This file contains all the generic wrapper functions
> // to be used by any PHP application.
> 
> switch($RDBMS)
> {
>    case 'mysql':
>       require_once('db.mysql.inc.php');
>       break;
>    case 'pgsql':
>       require_once('db.pgsql.inc.php');
>       break;
>    default:
>       exit('Invalid RDBMS Defined: $RDBMS');
>       break;
> }
> ---------------
> 
> 
> -- In user.inc.php --
> <?php
> // user.inc.php
> // This file contains all the functions required for a program
> // to interface with the user data.  The main script should not
> // know or care whether the user information is stored in a
> // database, flat files, or is hard coded.
> 
> require_once('db.inc.php'); // for generic db wrapper definitions
> 
> function get_user_info($userid)
> {
>    $query = "SELECT username, first_name
>                FROM users WHERE id='$userid'";
>    $res = db_query($query); // notice the generic wrapper
> 
>    $info = array();
> 
>    if($res)
>    {
>       $info = db_fetch_array($res, DB_ASSOC);
>    }
> 
>    return $info;
> }
> 
> ?>
> ----------------
> 
> 
> -- config.inc.php --
> <?php
> // config.inc.php
> // This file contains site specific configuration settings.
> 
> $RDBMS   = 'mysql';
> $DB_USER = 'username';
> $DB_PASS = 'password';
> $DB_HOST = 'localhost';
> 
> 
> $DEBUG_MODE = false;
> 
> $BASE_PATH = '/home/nikolai/public_html/bigaction.org/';
> $BASE_URL = '/';
> 
> require_once('db.inc.php');
> require_once('user.inc.php');
> ?>
> ----------------
> 
> -- bigaction.inc.php --
> <?php
> // bigaction.inc.php
> // This file defines functions which generate HTML for
> // bigaction.org.
> 
> require_once('user.inc.php');
> 
> function page_header($title)
> {
>   $hdr = <<<EOH
> <HTML>
> <HEAD>
>   <LINK rel="stylesheet" type="text/css" href="bigaction.css" />
>   <TITLE>$title</TITLE>
> </HEAD>
> <BODY>
> EOH;
> 
>   return $hdr;
> }
> 
> function user_greeting($userid)
> {
>   $info = get_user_info($userid);
> 
>   return "<span class=\"greeting\">Hello, "
>         . $info['first_name'] . "</span>\n";
> }
> ----------------
> 
> -- main.php --
> <?php
> // main.php
> // This file is where all the script execution logic is located.
> 
> require_once('config.inc.php');
> 
> require_once('bigaction.inc.php');
> 
> echo user_greeting($userid);
> 
> ?>
> ----------------
> 
> 
> It's a lot of work, but the benefit lies in that you can write a lot of
> utility code ONCE, and then use it again and again for every site you do
> after.  It dramatically increases your productivity.  Plus, it increases the
> stability of your site, since you've already written and tested all your
> utility code, so there's that much less that can cause problems later on.
> 
> Hope this helps,
> 
> nik
> 
> 
> 
> > PS. Google seems to do a poor job of watching Wrox, since when I
> > search for your name this site rarely comes up. However, you do
> > seem to be all over the place, elsewhere, working with Smarty,
> > then xml-java, then suggesting features like wc on the PHP Dev
> > list. You must work all the time. Do you ever sleep?
> 
> I sleep... sometimes too much, but it never feels like enough. =)  I don't
> actually do any PHP programming for work right now -- I've been immersed in
> the C++ world for a while.  If I had the time, I'd create a new
> bigaction.org site and post a lot of PHP tips/tricks/faqs, etc...  Sad thing
> is that there's nothing I can really do that hasn't already been done.  One
> of my main reasons for NOT creating a personal home page with programming
> language specific topics is because I'd really prefer to have one great
> central site for good content to be located.  It wouldn't be helpful to you,
> as a new programmer, to have to look at phpbuilder for one thing, php.net
> for another, burhan's site for something else, and my site for yet another
> thing.
> 
> Besides, I've got a girlfriend who's MUCH more rewarding to be with than my
> 'puter. =D
> 
> 
> take care,
> 
> nik
> 
> 
> 
Message #10 by "Nikolai Devereaux" <yomama@u...> on Tue, 17 Sep 2002 08:59:16 -0700
There's not really any hard and fast rules.  Make one thing clear, though --
spaghetti code is a phrase used describe code with lots of goto statements
and unclear trace of execution.

Functions calling functions calling functions is no big deal -- supposing
that each function does something useful, specific, and expected, given the
function name.  If I said that it's bad to have functions calling functions
calling functions before, look up that post again and see whether or not
there's additional context to it -- most likely, the goal of those functions
wasn't clearly defined, and I was suggesting you organize things a little
differently.


The getNavFromDb() function looks like it's called in the right place.
After all, you are in showNav(), which presumably needs to know what the nav
is!  My only suggestion would be to call it simply, getNav(), since it
really doesn't matter to the application (or the programmer USING the
function) where the nav info is located.


Some comments about your function, though --

> function showNav($section = 1) {
     $self = $_SERVER['PHP_SELF'];  // takes one line!

> 	// This function runs getNavFromDb and gets back a 2
> dimensional array that holds
> 	//  navId, navLinkText, navSection, navOOA,
> navLinksToNumber, navLinksToType from mcNavigation in each row.
> 	$nav = getNavFromDb($section);
> 	echo "<div class='dvclLinksBlock'>";
>
> 	for ($i=0; $i < count($nav); $i++) {
> 		if ($nav[$i][2] == $section) {

When wouldn't $nav[$i][2] == $section?  getNavFromDb() takes $section as a
parameter, which leads me to believe that if it returned ANYTHING, it would
only return the rows of the section you specified...

Also, while I'm here, why return a numerically indexed array?  It would be
more readable and maintainable if you returned a string indexed array.

Lemme suggest a simple rewrite of this part:

$navs = getNavFromDb($section);

foreach($navs as $nav)
{
   switch($nav['navLinksToType'])
   {
      case 'article':
      {
        $varname = 'articleId';
        break;
      }
      case 'catPage':
      {
        $varname = 'catPageId';
        break;
      }
      case 'builtInPage':
      {
         $varname = 'builtInPage';
         break;
      }
   }
   echo "<a href=\"{$self}?"
      . "{$varname}={$nav['navLinksToNumber']}\">"
      . $nav['navLinkText'] . "</a><br />\n";

}


hope this helps!

Nik

Message #11 by spam@k... on Thu, 19 Sep 2002 16:54:08 -0500
> Also, while I'm here, why return a numerically indexed array?  It would be
> more readable and maintainable if you returned a string indexed array.

Yes, I've been trying to figure a way to automaically create variables with names of the index. Not enough time today.






Message #12 by "Nikolai Devereaux" <yomama@u...> on Thu, 19 Sep 2002 15:03:17 -0700
> > Also, while I'm here, why return a numerically indexed array?
> > It would be more readable and maintainable if you returned a
> > string indexed array.
>
> Yes, I've been trying to figure a way to automaically create
> variables with names of the index. Not enough time today.

If your arrays are generated from db queries, you can simply use the
fetch_array() function instead of fetch_row().

for example, http://www.php.net/mysql_fetch_assoc

hth,

nik

Message #13 by spam@k... on Thu, 19 Sep 2002 17:11:54 -0500
> Also, while I'm here, why return a numerically indexed array?  
>It would be
> more readable and maintainable if you returned a string 
> indexed array.

As to why I started off writing PHP scripts always using mysql_fetch_row, my only defense is that is what they suggest to do in all
the PHP books I read. I've since decided to use mysql_fetch_array for everything, and anyway, the database class that I'll be using
from here on out uses fetch array. To that end, I plan on writing a function that automatically creates a variable that has the same
name as the index, and is then given the contents (the value of that key). 

I've another design question. If there are certain things that I do to practically all database returns, stripslashes() for
instance, and I want a function that routinely applies stripslashes to any db result, should I put that function in with the
database class? Or have a separate class for all the functions that massage db data, both going and coming out? Or just stick the
function in something like baseFunctions.php?  Should a database class only contain wrappers for PHP native calls, or is it okay to
fill it with a bunch of processing methods? Is there a rule of thumb that programmers often go by when they are wondering whether a
function belongs to a class? Should one be minimalist or maximalist? Small objects or big objects? 

Sorry for the open-ended nature of the question. If you've no answer or no time perhaps you could point to me an article or a book
that you respect. 



Message #14 by "Nikolai Devereaux" <yomama@u...> on Thu, 19 Sep 2002 15:20:22 -0700
> As to why I started off writing PHP scripts always using
> mysql_fetch_row, my only defense is that is what they suggest to
> do in all the PHP books I read. I've since decided to use
> mysql_fetch_array for everything, and anyway, the database class
> that I'll be using from here on out uses fetch array. To that
> end, I plan on writing a function that automatically creates a
> variable that has the same name as the index, and is then given
> the contents (the value of that key).

You mean like extract() ?
  http://www.php.net/extract

extract() basically does this:

foreach($array as $key => $value)
  $$key = $value;

it's nicer because it's a built in function (which usually means it executes
a little quicker than a php foreach() loop) and you can pass additional
handling parameters to tweak how it handles duplicate varnames, etc.


I don't have time to get into your other questions right now, but hopefully
I will by the end of today or tomorrow...

take care,

nik

Message #15 by "David Scott-Bigsby" <DScott-Bigsby@P...> on Thu, 19 Sep 2002 15:48:18 -0700
> > I plan on writing a function that automatically creates a
> > variable that has the same name as the index, and is then given
> > the contents (the value of that key).
>
> You mean like extract() ?
>
> extract() basically does this:
>
> foreach($array as $key =3D> $value)
>   $$key =3D $value;

Yuck! Maybe I'm old fashioned, but I prefer to have my variables 
explicitly defined in my code. This lets the data model drive the 
run-time variables. (shudder)

Why not simply go with mysql_fetch_assoc()? e.g.,

	$aRow =3D mysql_fetch_assoc($r);
	echo $aRow['FirstName'];

dsb

***************************************       
David Scott-Bigsby
Product Manager, Web Site and PEDN

PureEdge Solutions
The Leader in Secure XML e-Forms

v:250-708-8145  f:250-708-8010
1-888-517-2675   www.PureEdge.com
***************************************

Message #16 by spam@k... on Thu, 19 Sep 2002 18:01:19 -0500
> Yuck! Maybe I'm old fashioned, but I prefer to have my 
> variables explicitly defined in my code. This lets the data 
> model drive the run-time variables. (shudder)

It's awfully convenient when filling a page with data from a db return. 
Message #17 by "David Scott-Bigsby" <DScott-Bigsby@P...> on Thu, 19 Sep 2002 16:14:55 -0700
> > Yuck! Maybe I'm old fashioned, but I prefer to have my
> > variables explicitly defined in my code. This lets the data
> > model drive the run-time variables. (shudder)
>
> It's awfully convenient when filling a page with data from a
> db return.

I can see that "$FirstName" is a bit more convenient that 
"$aRow['FirstName']".

But there's a risk in having your data model lead to the automated 
creation of variables in your code.

In either case, a change in your data model requires a change in your 
code, e.g., if "FirstName" changes to "fname", then both "$FirstName" 
and "$aRow['FirstName']" would be unset when called. Failing to catch 
this isn't likely to cause serious trouble.

However, I could see cases where a column, e.g., "timestamp", is added 
to your table. If your code already had a variable "$timestamp", then 
using the extract() approach could lead to a pretty subtle bug.

Using an associative array (e.g., from mysql_fetch_assoc()) is, in 
effect, a way of controlling the scope of the dynamically created 
variables. All data-driven variables are created within the array, 
rather than in the script as a whole (or the function, etc., as a 
whole).

But to each their own.

dsb

***************************************       
David Scott-Bigsby
Product Manager, Web Site and PEDN

PureEdge Solutions
The Leader in Secure XML e-Forms

v:250-708-8145  f:250-708-8010
1-888-517-2675   www.PureEdge.com
***************************************
Message #18 by "Nikolai Devereaux" <yomama@u...> on Thu, 19 Sep 2002 16:52:04 -0700
> However, I could see cases where a column, e.g., "timestamp", is
> added to your table. If your code already had a variable
> "$timestamp", then using the extract() approach could lead to a
> pretty subtle bug.
>
> Using an associative array (e.g., from mysql_fetch_assoc()) is,
> in effect, a way of controlling the scope of the dynamically
> created variables. All data-driven variables are created within
> the array, rather than in the script as a whole (or the function,
> etc., as a whole).

This is yet another reason why I [over]use arrays for storing and organizing
data.

I dunno if you saw my TIP post about it a while back, but I would also
recommend using the array indexes rather than extracting the values into
variables.

If you further follow my advice/rants, you'll always use a function to get
things from the database.  If your column changed from "first_name" to
"fname", you can modify the db interface function accordingly without having
to change anything else in your code.


More plainly:

DB TABLE 'users'
id
username
first_name
last_name
password


// This function returns a numerically indexed array, where each
// index represents a user.  Each user is itself another array,
// with the following string indexes:
//    id, username, first_name, last_name, password
function get_users()
{
   $query = "SELECT id, username, first_name, ...";
   $users = array();
   $result = db_query($query);

   while($row = db_fetch_array($result, DB_ASSOC))
   {
      $users[] = $row;
   }

   return $users;
}


Now, the schema changes and "first_name" becomes "fname", and "last_name"
becomes "lname".  You would only have to change one line of code for your
entire site to cope with that change:


// This function returns a numerically indexed array, where each
// index represents a user.  Each user is itself another array,
// with the following string indexes:
//    id, username, first_name, last_name, password
function get_users()
{
   $query = "SELECT id, username,
                    fname as first_name,
                    lname as last_name, ...";

   $users = array();
   $result = db_query($query);

   while($row = db_fetch_array($result, DB_ASSOC))
   {
      $users[] = $row;
   }

   return $users;
}


> But to each their own.

Truer words were never spoken.

Message #19 by spam@k... on Fri, 20 Sep 2002 13:27:18 -0500
On Mon, 16 Sep 2002 11:19:18 -0700, "Nikolai Devereaux" 
> Each function should use generic database methods.
> Don't ever mix the HTML and SQL.

The following function, then, flunks both tests, as it makes a straight query to mysql, and then wraps the result in some HTML,
using another function that wraps results in HTML (using the function wrapInDiv, which wraps the content in a DIV tag and gives the
DIV whatever CSS class is specified).

I feel that by now I understand the importance of using generic database calls, and I intend to rewrite my code with my new
understanding. But I'm still trying to get the injunction against getting a result and mixing it with HTML in the same function.
You're saying, I think, that all such calls should be done in their own functions, and the function that outputs to the screen
should simply call it at the beginning? But why? So you can edit one without having to edit the other? In the below function the
first 4 lines of code should be in their own function? 


function showArticle($articleId) {

	connectMcToDb();
	$result = mysql_query("SELECT * FROM mcArticles WHERE articleId='$articleId'") or die("This article can not be shown at this
time.");
	$dbResult = dbResultIntoArray($result);
	$dbResult = processArray($dbResult, "stripslashes");

	for ($i=0; $i < count($dbResult); $i++) {
		$dbResult[$i][2] = nl2br($dbResult[$i][2]);
		wrapInDiv($dbResult[$i][1], "artilceHeadline");
		wrapInDiv($dbResult[$i][2], "articleMainContent");	
	}
}
Message #20 by spam@k... on Fri, 20 Sep 2002 13:40:52 -0500
> > However, I could see cases where a column, e.g., "timestamp", is
> > added to your table. If your code already had a variable
> > "$timestamp", then using the extract() approach could lead to a
> > pretty subtle bug.
> >
> > Using an associative array (e.g., from mysql_fetch_assoc()) is,
> > in effect, a way of controlling the scope of the dynamically
> > created variables. All data-driven variables are created within
> > the array, rather than in the script as a whole (or the function,
> > etc., as a whole).

That's a good argument, but still, something needs to be done to get arrays into simple variables before you print to the screen.
The problem is that PHP will not evaluate 2 dimensional arrays inside of an echo statement. It only evaluates the first dimension of
the array. Database returns are 2 dimensional. If you get a database return and want to print it to the screen with some HTML
formatting, the easiest way is to put the db return into simple variables and then use them inside of a big echo statement. I get
tired of doing that assigning by hand, but you're right to point out that using extract would lead to problems. 

As to the limits of PHP evaluation inside of an echo, you can run the code below and the final line will be "The dog is of the
species Array[0]"




// This tests to see if PHP will evaluate 2 dimensional arrays inside of echo statements. 

$dog = array();
$dog[] = "german shepard";
echo $dog[0];
echo "<br><br>";
$title = array();
$title[] = $dog;
echo "The dog is of the species $title[0][0]";





Message #21 by spam@k... on Fri, 20 Sep 2002 13:49:37 -0500
On Thu, 19 Sep 2002 16:52:04 -0700, "Nikolai Devereaux" 
> I dunno if you saw my TIP post about it a while back, but I would also
> recommend using the array indexes rather than extracting the values into
> variables.

I think I stumbled onto the benefits of putting db query results into arrays last year and have since used the following function.
My only frustration with this current system, as I just said in another post, is that inside of an echo statement PHP won't evaluate
2 dimensional arrays. 

function dbResultIntoArray($dbResult) {
$dbArray = array();
$dbRow = array();

for ($row = 0; $row < mysql_num_rows($dbResult); $row++) {
		$dbRow = mysql_fetch_array($dbResult);
		$dbArray[$row] = $dbRow;
}

return $dbArray;
}






Nik writes:
> // This function returns a numerically indexed array, where each
> // index represents a user.  Each user is itself another array,
> // with the following string indexes:
> //    id, username, first_name, last_name, password
> function get_users()
> {
>    $query = "SELECT id, username, first_name, ...";
>    $users = array();
>    $result = db_query($query);
> 
>    while($row = db_fetch_array($result, DB_ASSOC))
>    {
>       $users[] = $row;
>    }
> 
>    return $users;
> }

Okay, this does about what my function does, but with the attribute DB_ASSOC . I take it with this attribute added one could now
write something like $users[$i]["last_name"]. I can certainly see advantages in that. db_fetch_array() I assume is a very simple
wrapper for mysql_fetch_array(). 


Message #22 by "David Scott-Bigsby" <DScott-Bigsby@P...> on Fri, 20 Sep 2002 12:16:43 -0700
> The problem is that PHP will not evaluate 2
> dimensional arrays inside of an echo statement.

What you're talking about is, technically, not an echo statement but a 
double-quoted string, which can be used in other contexts than the echo 
function.

> It only
> evaluates the first dimension of the array. Database returns
> are 2 dimensional. If you get a database return and want to
> print it to the screen with some HTML formatting, the easiest
> way is to put the db return into simple variables and then
> use them inside of a big echo statement.

It depends on what you feel is the most work to write and maintain. I'm 
happy concatenating strings from literals and two dimension array 
variables, but if you're not, then you'll write code.

An alternate approach is to use list() to assign query results en masse, 
e.g.,

	list($fname, $lname, etc. ) =3D mysql_fetch_row($rPerson);
	echo "Dear $fname $lname, it's been too long!";

This way you can change your data model and your interface to it without 
(so long as your queries return the same fields in the same order) 
changing the portion of your script that transforms the data into HTML.

dsb

***************************************       
David Scott-Bigsby
Product Manager, Web Site and PEDN

PureEdge Solutions
The Leader in Secure XML e-Forms

v:250-708-8145  f:250-708-8010
1-888-517-2675   www.PureEdge.com
***************************************
Message #23 by "David Scott-Bigsby" <DScott-Bigsby@P...> on Fri, 20 Sep 2002 12:26:50 -0700
> beginning? But why? So you can edit one without having to
> edit the other? In the below function the first 4 lines of
> code should be in their own function?

Exactly. Then if you modify your data model, change your database or 
simply want to use the same query in multiple scripts, you can just call 
that function.

Compare yours....

> function showArticle($articleId) {
>
> 	connectMcToDb();
> 	$result =3D mysql_query("SELECT * FROM mcArticles WHERE
> articleId=3D'$articleId'") or die("This article can not be
> shown at this time.");
> 	$dbResult =3D dbResultIntoArray($result);
> 	$dbResult =3D processArray($dbResult, "stripslashes");
>
> 	for ($i=3D0; $i < count($dbResult); $i++) {
> 		$dbResult[$i][2] =3D nl2br($dbResult[$i][2]);
> 		wrapInDiv($dbResult[$i][1], "artilceHeadline");
> 		wrapInDiv($dbResult[$i][2], "articleMainContent");=09
> 	}
> }

...with this...

function showArticle($articleId)
{
	connectMcToDb();
=09
	if ($dbResult =3D selectArticle($articleID))
	{
		for ($i=3D0; $i < count($dbResult); $i++) {
			$dbResult[$i][2] =3D nl2br($dbResult[$i][2]);
			wrapInDiv($dbResult[$i][1], "artilceHeadline");
			wrapInDiv($dbResult[$i][2], "articleMainContent");=09
		}	=09
	}
	else
	{
		die("This article can not be shown at this time.");
	}
}


function selectArticle($articleID)
{
	$sql =3D "SELECT * FROM mcArticles WHERE articleId=3D'$articleId'";
	connectMcToDb();

	if ($result =3D mysql_query($sql))
	{
		$dbResult =3D dbResultIntoArray($result);
		return processArray($dbResult, "stripslashes");
	}
	else
	{
		return FALSE;
	}
}

Now it doesn't matter to showArticle() how selectArticle() gets the 
data, or to selectArticle() how shows the data. As long as the interface 
between them stays constant, you can tweak either one without buggering 
the other.

dsb

***************************************       
David Scott-Bigsby
Product Manager, Web Site and PEDN

PureEdge Solutions
The Leader in Secure XML e-Forms

v:250-708-8145  f:250-708-8010
1-888-517-2675   www.PureEdge.com
***************************************

Message #24 by "Nikolai Devereaux" <yomama@u...> on Fri, 20 Sep 2002 13:06:41 -0700
I'll reply to all three of your consecutive posts here...


> On Mon, 16 Sep 2002 11:19:18 -0700, "Nikolai Devereaux"
> > Each function should use generic database methods.
> > Don't ever mix the HTML and SQL.
>
> The following function, then, flunks both tests, as it makes a
> straight query to mysql, and then wraps the result in some HTML,
> using another function that wraps results in HTML (using the
> function wrapInDiv, which wraps the content in a DIV tag and
> gives the DIV whatever CSS class is specified).

You're right, it does.  David Scott-Bigsby posted a decent response to this,
so I'll leave it at that.  He knows what he's talking about.


> I feel that by now I understand the importance of using generic
   snip...
> But why? So you can edit one without having to edit the other?
> In the below function the first 4 lines of code should be in
> their own function?

Yes, more or less...  Any function that interfaces with the database should
NOT contain SQL -- it's job is to interface with the database.  Any function
that generates HTML (* see footnote) shouldn't contain any SQL.  That's not
it's job.  It's responsibilities include generating HTML based on input data
to the function.

I made a chart once which illustrates how I think files and functions should
be written:

+-----------------------------------------------------------------+
|   file    | outputs anything?  | contains HTML? | contains SQL? |
+-----------+--------------------+----------------+---------------+
| main file |       Yeep         |                |               |
| form inc  |                    |     Yeep       |               |
| db inc    |                    |                |     Yeep      |
+-----------------------------------------------------------------+




> I think I stumbled onto the benefits of putting db query results
> into arrays last year and have since used the following function.
> My only frustration with this current system, as I just said in
> another post, is that inside of an echo statement PHP won't
> evaluate 2 dimensional arrays.

That's not true -- you're just using the improper syntax.  More follows...

> As to the limits of PHP evaluation inside of an echo, you can run
> the code below and the final line will be "The dog is of the
> species Array[0]"

> echo "The dog is of the species $title[0][0]";

That's because PHP will only do variable substitution on arrays for the
first index, unless you use the curly-bracket syntax to tell PHP exactly
where variable substitution begins and ends.

echo "The dog is of the species {$title[0][0]}";


should work fine.
  http://www.php.net/types.string

> Okay, this does about what my function does, but with the
> attribute DB_ASSOC . I take it with this attribute added one
> could now write something like $users[$i]["last_name"]. I can
> certainly see advantages in that. db_fetch_array() I assume is a
> very simple wrapper for mysql_fetch_array().

db_xxxx is a generic wrapper (usually) for the php built in that it
corresponds to -- be it pgsql_xxxx or mysql_xxxx or whatever.


Again, read through dsb's posts as well.


> function dbResultIntoArray($dbResult) {
> $dbArray = array();
> $dbRow = array();
>
> for ($row = 0; $row < mysql_num_rows($dbResult); $row++) {
> 		$dbRow = mysql_fetch_array($dbResult);
> 		$dbArray[$row] = $dbRow;
> }
>
> return $dbArray;
> }


This is a nice utility function, but the reason I prefer the while() version
I suggested is because you don't make as many function calls.  In your
version, you call mysql_num_rows() for every iteration of the loop for the
($row < mysql_num_rows()) comparison.










*   Here's a big difference between how I code and how everyone ELSE
codes -- I never write functions which OUTPUT html; i only GENERATE it.  All
outputting is done in a main script which contains the core logic of the
page being built.  for example:


everyone else's way:
-- page_templates.php
<?php
function page_header($title)
{
   echo "<HTML><HEAD><TITLE>$title</TITLE></HEAD><BODY>\n";
}

...
?>
----------------------
-- main.php
<?php
include('page_templates.php');

page_header();
...
?>
----------------------



// my way
-- page_templates.php
<?php
function page_header($title)
{
   return "<HTML><HEAD><TITLE>$title</TITLE></HEAD><BODY>\n";
}

...
?>
----------------------

--- main.php
<?php

include('page_templates.php'); // for page_header/footer, etc.

echo page_header();
...
?>
----------------------

Message #25 by spam@k... on Fri, 20 Sep 2002 18:38:09 -0500
I've been using an ultra-simple password function for security. It works on PCs, and it seems to work on
some Macs. However, on some Macs, it doesn't work. On some the person can log in, and arrive at the control page, but then when they
choose an option, they get bounced back out to the login screen. The problem is as if the Macs were not allowing cookies to be set. 

Tonight I got to check it out for myself. I went to a friends house and used her Macintosh PowerBook to log in. Sure enough, I
wasn't able to get in. I got to the main screen, but when I choose any option I was bounced back out. I looked in her cookies and
found one for the site in question. When I opened it, much to my surprise, the only thing in it was PHPSESID and then a long number.
This using IE. 

Okay, another function sets up the session. So that cookie should be there. But why isn't the security cookie also there? 

function below. 


function checkPassword() {
	global $self, $password, $mcPassword, $pathToIndex, $nameOfDomain;
	setcookie('password', $password, time() + 3600, "/", $nameOfDomain);

	// $mcPassword is the password that is set in the config file or in the database.
	if ($password != $mcPassword){
		setcookie('password', $password, time() - 3600, "/", $nameOfDomain);
		echo "
		<table cellpadding='6px' border='1'>
		<tr><td>
		This part of the website is restricted to employees. 
		If you are not an employee, 
		<a href='$pathToIndex'>
		please click here to return to the main part of this site.
		</a>
		</td><td>
		<form method='post' action='$self'>
		Please type your password here:<br>
		<input type='password' name='password'><br>
		<input type='submit'>
		</form>
		</td></tr></table>
		";
               die();
	} 
}

  Return to Index