Location: PHPKode > scripts > Comment > comment/class_comment.php
<?PHP
/*
* Filename.....: class_comment.php
* Class........: comment
* Purpose......: Allow comments on different items
* Parameter....: none
* Erstellt am..: 2006-05-20
*       _  __      _ _
*  ||| | |/ /     (_) |        Wirtschaftsinformatiker IHK
* \. ./| ' / _ __  _| |_ ___   www.ingoknito.de
* - ^ -|  < | '_ \| | __/ _ \
* / - \| . \| | | | | || (_) | Peter Klauer
*  ||| |_|\_\_| |_|_|\__\___/  06136-909093
* mailto.......: hide@address.com
*
* Changes/Ă„nderungen:
*/


class comment
{

  var $cssdir = './css/'; // where is my stylesheet?
  var $id_for   = 0;
  var $code_for = '';

  /**
  * If the client already has made a comment on a specific
  * subject, he is not allowed to make another if
  * $prevent_multiple is true. However, he may edit his
  * already made comment.
  */
  var $prevent_multiple = true;

  /**
  * Trying to find links by the '://' indicator
  * Comments with links are not allowed.
  */
  var $prevent_spam = true;

  var $showcomments = false; // expand comment list without being asked

  # this class needs sqltable already installed and running!

  var $comments_per_page = 10;
  var $sqltable = 0;

  # tweaking section - - - - - - - - - - - - - - - - - - -

  var $newline = "\n";
  var $SQLTYPE = 'mysql'; // mssql works, too
  var $debug = false;
  var $comment_rows = 4; // height of comment input field
  var $comment_cols = 60; // width of comment input field

  var $before_insert = ''; // string before insert form
  var $after_insert = '';

  var $before_comments = ''; // string before comments table is shown
  var $after_comments = '';

  # callback function ( id_for, code_for, comment, nickname )
  var $onnew = ''; // callback function evaluated when new comment

  # callback function ( id_for, code_for, comment, nickname, old_comment )
  var $onchange = ''; // callback function evaluated when comment is changed

  # callback function ( id_for, code_for )
  var $onalias = ''; // callback function to prepare alias name

  var $edit_alias = true; // alias field can be edited by user
  var $show_alias = true; // alias field is shown

  # language specific - - - - - - - - - - - - - - - - - - -

  var $say_comment    = 'Comment';
  var $say_comments   = 'Comments';
  var $say_addcomment = 'Add a comment';
  var $say_submit     = 'Submit';
  var $say_nickname   = 'Nickname';
  var $say_update     = 'Update';
  var $say_updated    = 'Entry updated.';
  var $say_close      = 'Close (X)';
  var $say_nomultiple = 'Sorry, no multiple comments allowed.';
  var $say_entered    = 'First entered on';
  var $say_lastchanged= 'Last change';
  var $say_nolinks    = 'Sorry, no links allowed.';

  # internal - - - - - - - - - - - - - - - - - - - - - - - -

  var $funcname = ''; // for comment::error


  /**
  * You may have more than one comment-types on your websites:
  * Comments may be on articles, polls, designs, news or even on comments.
  * Using the $code_for "articles" you may have a comment for an article with id 13
  * and using the $code_for "polls" you may have a comment for a poll with id 13
  * in another table.
  *
  * @param integer $id_for = id of article in article-table
  * @param string $code_for = abbreviation for "kind-of-article" (may be empty)
  * @param rewource $sqltable = reference to an object of class sqltable
  * @param string $cssdir = Directory of the cssfile for the comments
  */
  function comment( $id_for, $code_for, &$sqltable,  $cssdir = './css/' )
  {

    $this->funcname = 'comment';

    if( ! is_dir( $cssdir ) )
    {
      $this->error("[$cssdir] is not a directory!" );
    }
    $this->cssdir = $cssdir;

    if( ! get_class( $sqltable ) == 'newsqltable')
    {
      $this->error( 'I need a reference to sqltable (http://www.phpclasses.org/browse/package/1981.html) to work properly!' );
    }
    $this->sqltable =& $sqltable;
    $this->id_for = $id_for;
    $this->code_for = $code_for;
    $this->sqltable->mousehighlight= false;

  } // eof comment (constructor)


  /**
  * Install the style sheet into the head section of the page.
  * Check whether the MYSQL-table exists and try installing it if missing.
  * As you see, it does not open any connection to a db here. The class assumes
  * that the sql connection is already open. The sql type is in var $this->SQLTYPE
  * Shall work with both mysql and mssql.
  */
  function install( )
  {

    $this->funcname = 'install';

    # just to be sure: add a slash / at the end of $this->cssdir if missing
    if( ! (substr( $this->cssdir, strlen($this->cssdir )-1, 1) == '/' ) ) $this->cssdir .= '/';
    if( ! file_exists( $this->cssdir.$this->code_for.'comment.css') )
    {
      #
      # Try to write it!
      #
      $css = '
      
/* css for class comment written on '.date( 'Y-m-d H:i:s' ).' */

.commentinput{ margin: 1em }

.commentinput label{
float:left;
width: 7em;
text-align:right;
margin: 0 1em 0 0;
}

.commenttopbar{
	background-color: #ccc;
	color: #000;
	border: solid 2px #888;
	margin: 0 0 1px 0;
}

.commentnickname{
	width: 20ex;
	font-size: 120%;
}

.commentdatetime{
	font-size: 80%;
	color: #888;
	width: 45ex;
	float: right;
}

.comment{
	margin:0 0 1ex 0;
}

.comment form{
	margin:0;
}

.comment textarea{
	width: 90%;
	background-color: #ddd;
	color: black;
	font-family:Arial, sans-serif;
	border: solid 1px #888;	
}

.comment span{
	display: block;
	background-color: #ddd;
	color: black;
	font-family:Arial, sans-serif;
	border: solid 1px #888;	
}
';


      $handle = fopen( $this->cssdir.$this->code_for.'comment.css', 'w' );
      if( fwrite( $handle, $css, strlen( $css ) ) === FALSE )
      {
        $this->error( 'Can not write CSS file ['.$this->cssdir.$this->code_for.'comment.css]');
      }
      fclose( $handle );

    } // end of if css file does not exist

    echo $this->newline.'<link rel="stylesheet" type="text/css" href="'.
    $this->cssdir.$this->code_for.'comment.css">';


    if( !class_exists('sqltable') ) $this->error( 'sqltable not loaded!' );
    if( ! get_class( $this->sqltable ) == 'sqltable')
    {
      $this->error( 'I need a reference to sqltable (http://www.phpclasses.org/browse/package/1981.html) to work properly!' );
    }

    #    $this->sqltable->showstart =
    #      isset( $_GET['showstart'.$this->code_for] ) ? $_GET['showstart'.$this->code_for] :
    #      isset( $_POST['showstart'.$this->code_for] ) ? $_POST['showstart'.$this->code_for] : 0;
    $this->sqltable->showcount = $this->comments_per_page;
    $this->sqltable->SQLTYPE = $this->SQLTYPE;
    $this->sqltable->instance = $this->code_for; // rename showstart and showcount
    $this->sqltable->third =& $this; // 3rd arg for udf
    $this->sqltable->width='100%'; // take all the space available
    $this->sqltable->showcaptions = false; // we rearrange everything into one cell

    switch( $this->SQLTYPE )
    {
      /**
      * The indexes are all needed. If you plan to have sql statements which
      * contain a "where" statement then be sure to have an index for every
      * column that is withing the "where" clause. You will slow down your
      * sql otherwise, resulting in a slow server response time.
      * Here the indexes are needed to check whether the client is allowed
      * re-editing or if a similar item already exists (POST data refreshed).
      */
      case 'mysql':

      mysql_query(

      "CREATE TABLE IF NOT EXISTS comments
      (
        `id` bigint(20) unsigned NOT NULL auto_increment,
        `id_for` bigint(20) unsigned NOT NULL default '0',
        `code_for` varchar(8) NOT NULL default '''''',
        `datetime` datetime NOT NULL default '0000-00-00 00:00:00',
        `lastchanged` datetime NOT NULL default '0000-00-00 00:00:00',
        `nickname` varchar(15) NOT NULL default '',
        `comment` longtext NOT NULL,
        `ip` varchar(15) NOT NULL default '',
        `dns` varchar(180) NOT NULL default '',
        `user_agent` varchar(180) NOT NULL default '',
        `hash` varchar(32) NOT NULL default '',
        `validated` tinyint(3) unsigned NOT NULL default '0',
        PRIMARY KEY  (`id`),
        KEY `id_for` (`id_for`),
        KEY `code_for` (`code_for`),
        KEY `datetime` (`datetime`),
        KEY `ip` (`ip`),
        KEY `user_agent` (`user_agent`),
        KEY `nickname` (`nickname`),
        KEY `validated` (`validated`),
        KEY `hash` (`hash`)
      ) TYPE=MyISAM AUTO_INCREMENT=1") ;


      break;

      case 'mssql':

      mssql_query(
      "

      -- this will seldom work because of missing rights. Copy this text
      -- and let it execute in the SQL Query Analyzer
      -- if you work with mssql, you need to know what you do,
      -- sorry.

      IF NOT EXISTS( SELECT NAME FROM SYSOBJECTS WHERE NAME='comments' )
      BEGIN

      CREATE TABLE [comments] (
    	[id] [bigint] IDENTITY (1, 1) NOT NULL ,
    	[id_for] [bigint] NOT NULL ,
    	[code_for] [varchar] (8) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
    	[datetime] [datetime] NOT NULL ,
    	[lastchanged] [datetime] NOT NULL ,
    	[nickname] [varchar] (15) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
    	[comment] [text] COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
    	[ip] [varchar] (15) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
    	[dns] [varchar] (180) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
    	[user_agent] [varchar] (180) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
    	[hash] [varchar] (32) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
      [validated] [tinyint] not null
      ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
      CREATE  UNIQUE  CLUSTERED  INDEX [comment_id] ON [comments]([id]) WITH  PAD_INDEX  ON [PRIMARY]
      ALTER TABLE [comments] ADD
      	CONSTRAINT [DF_comments_id_for] DEFAULT (0) FOR [id_for]
      ALTER TABLE [comments] ADD
      	CONSTRAINT [DF_comments_validated] DEFAULT (0) FOR [validated]

       CREATE  INDEX [comment_id_for] ON [comments]([id_for]) ON [PRIMARY]
       CREATE  INDEX [comment_code_for] ON [comments]([code_for]) ON [PRIMARY]
       CREATE  INDEX [comment_ip] ON [comments]([ip]) ON [PRIMARY]
       CREATE  INDEX [comment_user_agent] ON [comments]([user_agent]) ON [PRIMARY]
       CREATE  INDEX [comment_nickname] ON [comments]([nickname]) ON [PRIMARY]
       CREATE  INDEX [comment_validated] on [comments]([validated]) on [PRIMARY]
       CREATE  INDEX [comment_hash] on [comments]([hash]) on [PRIMARY]
       GRANT  SELECT ,  UPDATE ,  INSERT ,  DELETE  ON [comments]  TO [public]

       END

      ");


      break;

      default: $this->error( "Wrong SQLTYPE: [$this->SQLTYPE]" );


    }

  }


  /**
  * Output an error and terminate
  * @param string $what = error message
  */
  function error( $what )
  {

    die( "<br>COMMENT::$this->funcname() <b>$what</b>" );

  }


  /**
  * temporal support function
  */
  function showsummary()
  {

    $this->put();

  }


  /**
  * Shows, how many comments there are for this subject.
  * Outputs a link to the comments list.
  * Outputs comments list
  * @param boolean $inputbox = whether to show an input field or not
  */
  function put()
  {

    global $_SERVER; // not always superglobal!?

    $p = $_SERVER['PHP_SELF'];
    $q = $_SERVER['QUERY_STRING'];

    $this->funcname = 'showsummary';

    #
    # insert new comment
    #

    if( isset( $_POST['savecomment'] ) and ($_POST['savecomment'] == '1' ) )
    {

      # mssql and mysql have different date functions. I take the PHP date for that.
      $dt = date('Y-m-d H:i:s');

      $ip = $_SERVER['REMOTE_ADDR'];
      $dns = gethostbyaddr($ip);
      $ua = $_SERVER['HTTP_USER_AGENT'];

      # get posts
      $nickname = trim( $_POST['nickname'] );
      $nickname = $this->checkspam($nickname);


      $comment = trim($_POST['comment']);

      $comment = $this->checkspam($comment);
      $comment = stripslashes( $comment );
      $comment = htmlentities( $comment );
      $comment = str_replace( "'", '&#039;', $comment );
      $comment = str_replace( '\\', '&#092;', $comment );



      $hash = md5( $comment );

      # empty name or comment? Go back.
      $ok = true;
      if( strlen( $nickname ) == 0 ) $ok = false;
      if( strlen( $nickname ) > 15 ) $nickname = substr( $nickname, 0, 15 );
      if( strlen( $comment ) == 0 ) $ok = false;

      if( $ok )
      {

        # is there already such a comment (double trouble when refreshing post data)
        $anzahl = 0;

        # mssql cannot compare TEXT columns.
        # that is why a md5 hash field is in the table and this hash is compared instead.
        $query = "select count(*) from comments where ".
        "nickname='$nickname' and ip='$ip' and hash='$hash' ".
        "and id_for='$this->id_for' and code_for='$this->code_for' ".
        "and user_agent='$ua'";


        $r = $this->execute( 'query', $query );
        if( $r and $this->execute( 'num_rows', $r ) == 1 )
        {
          list( $count ) = $this->execute( 'fetch_row', $r );
          $this->execute( 'free_result', $r );
        }

        #
        # save the comment when it does not exist yet
        #
        if( $count == 0 )
        {

          #
          # if there is a function comment::onalias
          # and the user is not allowed to change the name ( comment::edit_alias == false )
          # (because we are in an intranet (AD) and the name does not need to be changed)
          # then just call the function again to receive the name.
          # Else take what you get.
          #
          if( $this->edit_alias == false and strlen(trim( $this->onalias ) )> 0 and function_exists( $this->onalias ) )
          {
              $nickname = eval( 'return('.$this->onalias.'('.$this->id_for.', \''.$this->code_for."'));");
          }

          $query =
          "insert into comments ".
          "(id_for, code_for, datetime, lastchanged, nickname, comment, ip, dns, user_agent, hash) ".
          "values ".
          "('$this->id_for','$this->code_for', '$dt', '$dt', '$nickname', '$comment', '$ip', '$dns', '$ua', '$hash')";

          $r = $this->execute( 'query', $query );

          $_GET['addcomment'] = 0;

          #
          # if comment::onnew is set, then evaluate it!
          # the callback function receives id_for and code_for as parameters.
          #
          if( strlen( trim( $this->onnew ) ) > 0 and function_exists( $this->onnew ))
          {
            #
            # The target function will output all necessary user information, if any.
            #
            eval( 'return('.$this->onnew.'('.$this->id_for.', \''.$this->code_for."', '$comment', '$nickname' ));");

          }

        }
        else
        {
          # just do nothing and throw it away!
        }

      }

    }


    #
    # Update a comment
    #
    if( isset($_POST['updatecomment']) and $_POST['updatecomment']==1)
    {

      $update = 0; // some checks against tampered data
      $today = date('Y-m-d');

      #
      # Check if the useragent, date, ip and nickname fit together.
      # If yes, then let the user update his input.
      # Otherwise, just display the text.
      #
      $id_comment = $_POST['id_comment'];
      $dt = $this->sqlisodate('datetime');
      $lc = $this->sqlisodate('lastchanged');
      $query = "select $dt, ip, user_agent, comment, nickname, hash, $lc from comments where id='$id_comment'";
      $r = $this->execute('query',$query);
      if( $r and $this->execute('num_rows', $r ) == 1 )
      {
        list( $datetime, $ip, $user_agent, $old_comment, $nickname, $old_hash, $old_lastchanged ) = $this->execute('fetch_row', $r );
        $this->execute( 'free_result', $r );

        # this could be a long "AND" statement
        if( strpos( '@'.$datetime, $today ) > 0 )
        {
          if( $_SERVER['REMOTE_ADDR'] == $ip )
          {
            if( $_SERVER['HTTP_USER_AGENT'] == $user_agent )
            {
              $update = 1;

            } // same user agent

          } // correct $ip

        } // $datetime is $today

        if( $update == 1 )
        {

          $comment = trim($_POST['comment']);

          $comment = $this->checkspam($comment);

          $comment = stripslashes( $comment );
          $comment = htmlentities( $comment );
          $comment = str_replace( "'", '&#039;', $comment );
          $comment = str_replace( '\\', '&#092;', $comment );

          $hash = md5( $comment );
          if( $hash <> $old_hash )
          {

            $lastchanged = date( 'Y-m-d H:i:s' ); // different in mysql and mssql, use PHP!

            if( $this->execute( 'query',
            "update comments set comment='$comment', hash='$hash', ".
            "lastchanged='$lastchanged' where id='$id_comment'") )
            {
              echo $this->say_updated ;
            }

            #
            # if comment::onchange is set, then evaluate it!
            # the callback function receives id_for, code_for and old_comment as parameters.
            #
            if( strlen( trim( $this->onchange ) ) > 0 and function_exists( $this->onchange ))
            {


              #
              # The target function will output all necessary user information, if any.
              #
              eval( 'return('.$this->onchange.'('.$this->id_for.', \''.$this->code_for."','$comment', '$nickname', '$old_comment'));");

            } // end if( has callback function )
          } // end if( $hash <> $old_hash ) check if it is still the same message

        } // end if( $update == 1 )
      } // end if( $r and $this->execute('num_rows', $r ) == 1 )
    } // end if( isset($_POST['updatecomment']) and $_POST['updatecomment']==1)



    #
    # Official comments link
    #
    echo '<a name="comments"></a>';
    $numcomments = $this->getcount();

    if( $numcomments > 0 )
    {
      $what = ( $this->showcomments or (isset($_GET['showcomments'] ) and $_GET['showcomments'] == '1' ) ) ? 0 : 1;
      $anchor = $what == 0 ? '#comments' : '#commentsqltable';
      $q2 = $this->sqltable->adjust_query_string( $q, 'showcomments='.$what );
      $link_start = "<a href='$p?$q2$anchor' title='$this->say_comments'>";
      $link_end = '</a>';
    }
    else
    {
      $link_start = '';
      $link_end = '';
    }
    echo "$link_start$this->say_comments: $numcomments$link_end ";


    #
    # if no infobox, say add comment
    #
    if(!isset($_GET['addcomment']) or $_GET['addcomment'] == '0' )
    {
      if( $this->prevent_multiple and $this->client_made_comment_today() )
      {
        echo $this->say_nomultiple;
      }
      else
      {
        $qs = $this->sqltable->adjust_query_string( $q, 'addcomment=1' );
        echo "<a href='$p?$qs#comments'>$this->say_addcomment</a>";
      }

    }


    #
    # having an empty line between (text) and (input box or comments) is nice
    #
    $x = 0;
    $x += ( isset( $_GET['showcomments'] ) ? intval($_GET['showcomments']) : 0 );
    $x += ( isset( $_GET['addcomment']   ) ? intval($_GET['addcomment']  ) : 0 );
    if( $x > 0 ) echo '<br><br>';


    #
    # Show inputbox
    #
    if(isset($_GET['addcomment']) and $_GET['addcomment'] == '1' )
    {
      $this->inputbox();
    }


    #
    # show comments in sqltable
    #
    if( $this->showcomments or ( isset( $_GET['showcomments']) and $_GET['showcomments'] == '1' ) )
    {
      # date is different on mysql and mssql.
      # to have the iso sql date, mysql does not need any help.
      # mssql is different.
      # use a switch -statement if more SQLTYPEs arrive

      $datesql = $this->sqlisodate('datetime').', '.
      $this->sqlisodate('lastchanged'); // get a valid date sql string for iso date YYYY-mm-dd HH:ii:ss

      $query = "select id, $datesql, nickname, comment, ip, dns, user_agent from comments where id_for='$this->id_for'
     and code_for='$this->code_for' order by datetime desc";

      $r = $this->execute( 'query', $query );
      if( $r and  ( $this->execute( 'num_rows', $r ) > 0 ) )
      {

        $this->sqltable->udf['datetime'] = 'comment::udf_commentsarrangedata';

        $this->sqltable->hidden['nickname'] = 1;
        $this->sqltable->hidden['ip'] = 1;
        $this->sqltable->hidden['dns'] = 1;
        $this->sqltable->hidden['id'] = 1;
        $this->sqltable->hidden['user_agent'] = 1;
        $this->sqltable->hidden['comment'] = 1;
        $this->sqltable->hidden['lastchanged'] = 1;

        $this->sqltable->fillup = false;
        $this->sqltable->index = false;

        echo $this->before_comments;

        echo '<a name="commentsqltable"></a>';

        $this->sqltable->anchor = '#commentsqltable';

        $this->sqltable->put( $r );

        $this->sqltable->anchor = '';

        echo $this->after_comments;
        $this->execute( 'free_result', $r );
      }

    }




  } // eof comment::showsummary()


  /**
  * Output form for input or
  * write the POST data into the table.
  */
  function inputbox()
  {

    global $_SERVER;

    if( $this->prevent_multiple and $this->client_made_comment_today() )
    {
      # sorry, no inputbox possible!
      echo $this->before_insert;
      echo $this->say_nomultiple;
      echo $this->after_insert;
    }
    else
    {

      $ps = $_SERVER['PHP_SELF'];
      $qs = $_SERVER['QUERY_STRING'];

      $qs = $this->sqltable->adjust_query_string( $qs, 'addcomment=0' );

      #
      # The following avoids the generation of &amp;amp;
      #
      $qs = str_replace( '&amp;','&', $qs ); # make &amp; to &
      $qs = str_replace( '&', '&amp;', $qs ); # make & to &amp;

      echo $this->before_insert;

     
      $nickname = '';
      
      ########
      # For your INTRANET:
      # Get a hint about the users' name
      # user defined callback function checks remote_user or similar server variable of the intranet
      #
      if( strlen( trim( $this->onalias ) ) > 0 and function_exists( $this->onalias ) )
      {
      
        $nickname = eval( 'return('.$this->onalias.'('.$this->id_for.', \''.$this->code_for."'));");
        
      }
      
      
      echo "<table summary='' width='100%'><tr><td><big>$this->say_addcomment</big></td><td align='right'>
         <a href='$ps?$qs#comments'>$this->say_close</a></td></tr></table>

         <div class='commentinput'><form action='$ps?$qs#comments' method='POST'>";
      
      if( $this->show_alias )
      { 
          echo "
           <label for='idname'>$this->say_nickname</label>";
          
        if( $this->edit_alias )
        {
          
          echo "
           <input type='text' name='nickname' id='idname' size='15' maxlength='15' value='$nickname'><br>";
        }
        else 
        {
          echo "
          <span id='idname'>$nickname</span><input type='hidden' name='nickname' value='$nickname'><br>";
        }
          
      }
      else 
      {
        echo "
        <input type='hidden' name='nickname' value='$nickname'>";
      }
       
      echo "
         <label for='idcomm'>$this->say_comment</label>
         <textarea name='comment' id='idcomm' rows='$this->comment_rows' cols='$this->comment_cols'></textarea><br>
         <input type='hidden' name='savecomment' value='1'>
         <label for='idsubm'>&nbsp;</label><input type='submit' name='btn' value='$this->say_submit' id='idsubm'>
         </form></div>";

      echo $this->after_insert;

    }

    echo '<br>';



  } // eof comment::inputbox


  /**
  * Execute a mysql or mssql or whateversql statement.
  * Take any number of arguments.
  * First arg is name of sql-function to execute:
  * say "query" for mysql_query or mssql_query
  * Second and following args are params for sql-function.
  *
  * @param variing multiple
  * @return resource  sql result
  */
  function execute(  )
  {

    $this->funcname = 'execute';
    $numargs = func_num_args();

    if( $numargs > 0 )
    {

      $args = func_get_args();
      $func = $args[0].'(';

      if( strpos( "+$func", '@' ) === false )
      {
        $at = '';
      }
      else
      {
        $at = '@';
        $func = substr( $func,1 );
      }

      $func = $at . $this->SQLTYPE.'_'.$func;

      $anz  = count( $args );
      for( $i = 1; $i < $anz; $i++ )
      {
        $func = str_replace( '"',"'",$func );
        if( is_resource($args[$i]) )
        {
          $varname = 'resource'.$i;
          global $$varname;
          $$varname = $args[$i];
          $func .= '$'.$varname;
        }
        else
        {
          $func .= '"'. $args[$i].'"';
        }

        if( $i < ( $anz-1 ) ) $func .= ','; // Separate entries with a comma

      }

      $func .= ')'; // close bracket
      $s = 'return( '.$func.');';
      if( $this->debug) echo "<br>eval: $s";
      $val = eval( $s );
      if( $this->debug ) echo "<br>$s => $val<br>";

    }

    return $val;

  } // eof comment::execute()


  /**
  * UDF for sqltable column "datetime"
  * Used to arrange multiple columns into one cell
  * @param string $a = original cell value
  * @param object $sqlrowvars = key-value-paired array
  * @param object $myself = initialized object of comment ($this)
  */
  function udf_commentsarrangedata($a, $sqlrowvars, $myself)
  {

    static $counter = 1;

    global $_SERVER;

    #
    # top row of comment contains nickname and dates
    #
    $s1 = '<a name="comment'.$counter.'"></a><div class="commenttopbar">'.
    '<table width="100%" summary="commentheadline"><tr><td class="commentnickname">'.
    ($myself->show_alias ? $sqlrowvars['nickname'] : '' ).
    '</td><td align="right" class="commentdatetime">'.$myself->say_entered.': '.
    $sqlrowvars['datetime'].'<br>';

    if( $sqlrowvars['lastchanged'] <> $sqlrowvars['datetime'] )
    {
      $changed = substr( $sqlrowvars['lastchanged'], 10 );
      $s1 .=  $myself->say_lastchanged.': '.$changed;
    }

    $s1 .= '</td></tr></table></div>';


    $text = $sqlrowvars['comment'];

    $edit = 0;
    $today = date( 'Y-m-d' );

    $ps = $_SERVER['PHP_SELF'];
    $qs = $_SERVER['QUERY_STRING'];
    #
    # The following avoids when tidying the generation of &amp;amp;
    #
    $qs = str_replace( '&amp;','&', $qs ); # make &amp; to &
    $qs = str_replace( '&', '&amp;', $qs ); # make & to &amp;

    #
    # Check if the useragent, date, ip and nickname fit together.
    # If yes, then let the user edit his input.
    # Otherwise, just display the text.
    #
    if( strpos( '@'.$sqlrowvars['datetime'], $today ) > 0 )
    {
      if( $_SERVER['REMOTE_ADDR'] == $sqlrowvars['ip'] )
      {
        if( $_SERVER['HTTP_USER_AGENT'] == $sqlrowvars['user_agent'] )
        {
          $edit = 1;
        }
      }
    }

    $begin = '<div class="comment">';

    if( $edit == 1 )
    {
      $s = "<form action='$ps?$qs#comment$counter' method='POST'>
      <textarea name='comment' rows='$myself->comment_rows' cols='$myself->comment_cols'>$text</textarea>
      <input type='hidden' name='id_comment' value='".$sqlrowvars['id']."'>
      <input type='hidden' name='updatecomment' value='1'>
      <input type='submit' name='btn' value='$myself->say_update'>
      </form>";

    }
    else
    {
      $s = '<span>'.$text.'</span>'; // span for css
    }

    $end = '</div>';

    $counter ++; // increase at each row

    return $begin.$s1.$s.$end;

  } // eof udf for sqltable comment::udf_commentsarrangedata


  /**
  * count() only displays $this->say_comments along with
  * the number of comments and does
  * nothing else. No links. No lights.
  */
  function count()
  {

    echo $this->say_comments.': '.$this->getcount();

  } // eof comment::count()


  /**
  * How much is inside? See www.cockeyed.com for the answer.
  * Get the count of comments
  * for $this->code_for and $this->id_for
  * @return integer
  */
  function getcount()
  {

    $result = 0;

    $query = 'select count(*) from comments where id_for=\''.$this->id_for.
    '\' and code_for=\''.$this->code_for.'\'';

    $r = $this->execute('query', $query );

    if( $r and $this->execute( 'num_rows', $r ) == 1 )
    {

      list( $result ) = $this->execute( 'fetch_row', $r );
      $this->execute( 'free_result' , $r );

    }

    return $result;

  } // eof comment::getcount()


  /**
  * Make the sql return an ISO date YYYY-MM-DD HH:II:SS which is always the
  * case for mysql, afaik but you need to convert things for mssql
  * @param string $which = name of the date field
  * @return string sqlstatement
  */
  function sqlisodate($which, $as = true)
  {

    $result = $which;  // for mysql

    $lb = $this->SQLTYPE == 'mssql' ? '[' : '';
    $rb = $lb == '[' ? ']' : '';

    switch( $this->SQLTYPE )
    {
      case 'mssql':
      $result = 'convert( varchar, '.$lb.$which.$rb.', 20 ) ';
      if( $as ) $result .= 'as '.$lb.$which.$rb;
      break;
      # put other SQLTYPEs here
    }

    return $result;

  } // eof comment::sqlisodate()


  /**
  * if prevent_multiple is ON, then this function will stop
  * a client from entering multiple comments
  *
  * @return boolean true if the client did already
  */
  function client_made_comment_today()
  {
    #
    # Test to see if the client already has made a comment
    # - does the "client" (= ip + user_agent)
    # - today (front part of datetime)
    # - about this subject (code_for, id_for)
    # - have a comment in the table?
    #

    global $_SERVER;

    $count = 0;

    $ip = $_SERVER['REMOTE_ADDR'];
    $ua = $_SERVER['HTTP_USER_AGENT'];
    $today = date( 'Y-m-d' ).'%';
    $dt = $this->sqlisodate( 'datetime', false );

    $query = 'select count(*) from comments where '.
    "code_for='$this->code_for' and id_for='$this->id_for'".
    " and $dt like '$today' and ip='$ip' and user_agent='$ua' ";

    if( $this->debug ) echo "<pre>$query</pre>";

    $r = $this->execute('query', $query );
    if( $r and $this->execute( 'num_rows', $r ) == 1 )
    {
      list( $count ) = $this->execute( 'fetch_row', $r );
      $this->execute( 'free_result', $r );
    }

    return ( $count > 0 ? true : false );


  } // eof comment::client_made_comment_today()

  /**
  * Anti "drugs guestbook spam"
  * Kill string completely if there is an indicator for a link inside!
  * @param string $s = string to test
  * @return string
  */
  function checkspam( $s )
  {
    if( $this->prevent_spam )
    {
      # link found ?
      if( strpos( $s, '://' ) > 0 )
      {
        $s = $this->say_nolinks;
      }
    }

    return $s;

  } // eof comment::checkspam()


} // eoc comment

?>
Return current item: Comment