Zum Inhalt springen

[Lösung] CHC_Forum mit Captcha Funktion

Erstellt am 3. Juli 2007 · 14 Antworten · letzte Antwort am 30. November 2007

Tags: PHP, Sicherheit, Tipp

nicolaibassdh ·

Hallo zusammen,

ich war auf der Suche nach einer Lösung für ein Spam-Problem in einem offenen CHC Forum.

Habe mir nun eine Captcha Funktion mit eingebaut. Hier eine kleine Anleitung falls jemand ähnliches plant:

1. Extension "captcha" installieren.

Den Code in in der Datei /ext/captcha/captcha/captcha.php habe ich dann mit folgenden Code überschrieben:

<?php
session_start();
function strrand($length)
{
	$str = "";

	while(strlen($str)<$length){
	$random=rand(48,122);
	#if( ($random>47 && $random<58-)  ){
	if (ereg('[A-Za-z]',chr($random)))
		$str.=chr($random);
	#}

	}

	return $str;
}

$imgHeight = 20;
$imgWidth = 50;

$text = $_SESSION['tx_captcha_string'] = strrand(5);
$img_number = imagecreate($imgWidth,$imgHeight);
$backcolor = imagecolorallocate($img_number,244,244,244);
$textcolor = imagecolorallocate($img_number,0,0,0);
$white = imagecolorallocate($img_number, 0xFF, 0xFF, 0xFF);

imagefill($img_number,0,0,$backcolor);

Imagestring($img_number,5,1,1,$text,$textcolor);

        //some obfuscation
        for ($i=0; $i<2; i="" x1="" imgwidth="" -="" 1="" y1="" roundimgheight="" 10="" x2="" roundimgwidth="" y2="" imgheight="" imagelineimg_number="" white="" rand1="" cx="" 50="" 25="" cy="" w="" 24="" imagearcimg_number="" 360="" headercontent-type:="" imagepng="" imagepngimg_number="">

2. Anpassung CHC Forum

2.1 Anpassung Datei /ext/chc_forum/class.tx_chcforum_form.php anpassen
In der Datei habe ich folgende Änderungen vorgenommen:
function tx_chcforum_form (ca. Zeile 75) um folgende Zeile erweitert:

$captchaHTMLoutput = t3lib_extMgm::isLoaded('captcha') ? '<img src="'.t3lib_extMgm::siteRelPath('captcha').'captcha/captcha.php" alt="" />' : '';

In der gleichen Funktion label_array um folgendes Feld erweitert:

'label_captcha' => t3lib_extMgm::isLoaded('captcha') ? '<img src="'.t3lib_extMgm::siteRelPath('captcha').'captcha/captcha.php" alt="" />' : '',

Funktion function validate() (ca. Zeile 485) um folgende Zeilen erweitert:

if (t3lib_extMgm::isLoaded('captcha'))	{
				session_start();
				$captchaStr = $_SESSION['tx_captcha_string'];
				$_SESSION['tx_captcha_string'] = '';
			} else {
				$captchaStr = -1;
			}
			
			if($_POST['captcha'] != $captchaStr) {
				$this->error['captcha'] = 'Please repeat the correct code!';
			} else {
				$valid_captcha = true;
			}

Dann im Code mal nach folgender Zeile suchen:

if ($valid_name == true && $valid_text == true && $valid_subject == true &&

Diese habe ich dann noch mit folgender Abfrage erweitert:

&& $valid_captcha == true

Das war es in dieser Datei

3. Template anpassen
Dafür die Datei /ext/chc_forum/pi1/templates/post_form.tpl öffnen und an gewünschter Stelle folgendes eintragen:

Repeat code: *<input type="text" size="30" name="captcha" value="" /><br />
{label_captcha}

OK, der hier gezeigte PHP Code ist nicht ganz Typo3 Konform aber es läuft ^^

Hoffe irgendwem damit geholfen zu haben.

Viele Grüße

Nic.

latschma ·

Hallo

Vielen Dank für diese Anleitung.

Hatte versucht die ext sr_freecap zu verwenden, wurde mir aber nicht klar wo die php-Änderungen hinein müssen.

Mit Deiner Anleitung klappt es:

Die ext captcha unverändert belassen (captcha.php nicht geändert, funktionierte sonst nicht).

Die Datei /ext/chc_forum/class.tx_chcforum_form.php
sieht jetzt so aus:

<?php
	 
	/***************************************************************
	*  Copyright notice
	*
	*  (c) 2004 Zach Davis (zach@crito.org)
	*  All rights reserved
	*
	*  This script is part of the TYPO3 project. The TYPO3 project is
	*  free software; you can redistribute it and/or modify
	*  it under the terms of the GNU General Public License as published by
	*  the Free Software Foundation; either version 2 of the License, or
	*  (at your option) any later version.
	*
	*  The GNU General Public License can be found at
	*  http://www.gnu.org/copyleft/gpl.html.
	*
	*  This script is distributed in the hope that it will be useful,
	*  but WITHOUT ANY WARRANTY; without even the implied warranty of
	*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	*  GNU General Public License for more details.
	*
	*  This copyright notice MUST APPEAR in all copies of the script!
	***************************************************************/
	/**
	* The form class is responsible for displaying the form and handling
	* the form submission. All insertions to the post, conference, category,
	* and thread tables take place in this class, in the submit function. The
	* only method that gets called publicly is the handle_form method -- more or
	* less everything else takes place internally (at least, that was the original
	* plan -- I need to look back over this class and make sure that's still the
	* case).
	*
	* @author Zach Davis <zach@crito.org>
	*/
	class tx_chcforum_form extends tx_chcforum_pi1 {
		 
		var $name; // post author name
		var $username;
		var $email; // post author email
		var $fe_user_uid;
		 
		// following get passed via post and are inherited from display object.
		var $view;
		var $cat_uid;
		var $conf_uid;
		var $thread_uid;
		var $where;
		var $stage;
		var $preview;
		var $text;
		var $subject;
		 
		var $button; // text for the button
		var $label_array; // a constant, set in the constructor for the class.
		var $action; // a constant, refers to form action url.
		var $cObj;
		
		var $html_out;

 		// Emoticon code container
 		var $emoticonCode = null;
		 
		// For dev purposes ONLY
#		var $lorem_forum = 10000;
#		var $lorem_forum_count = 1;

		
	 /**
	  * Constructor for form object. The entire display object gets passed here.
	  * This is probably inefficient, and it should probably be changed.
		*
		* @param object $display_object: the display object gets passed to this form because we need to many of it's properties to process the form correctly. However, this can probably be trimmed down somewhat.
		* @return void
	  */
		function tx_chcforum_form($display_object) {
			 
			// Setting the form constants
			$this->cObj = $display_object->cObj;
			$this->conf = $this->cObj->conf;

			// bring in the fconf.
			$this->fconf = $this->cObj->fconf;
			#if (intval(phpversion()) < 5) unset($this->cObj->fconf);

			// bring in the user object.
			$this->user = $this->fconf['user'];

			$this->internal['results_at_a_time'] = 1000;

			// get any params from typoscript -- used for forum / tt_news integration.
			if ($this->conf['chcAddParams']) {
    			$paramArray = tx_chcforum_shared::getAddParams($this->conf['chcAddParams']);
			
                  // 05/07/07 function tx_chcforum_form (ca. Zeile 75) um folgende Zeile erweitert:
                  $captchaHTMLoutput = t3lib_extMgm::isLoaded('captcha') ? '<img src="'.t3lib_extMgm::siteRelPath('captcha').'captcha/captcha.php" alt="" />' : '';
                  }	
			$this->action = htmlspecialchars($this->pi_getPageLink($GLOBALS['TSFE']->id,'',$paramArray));
			$this->label_array = array ('label_name' => tx_chcforum_shared::lang('form_label_name'),
                  // 05/07/07 In der gleichen Funktion label_array um folgendes Feld erweitert:
                        'label_captcha' => t3lib_extMgm::isLoaded('captcha') ? '<img src="'.t3lib_extMgm::siteRelPath('captcha').'captcha/captcha.php" alt="" />' : '',
				'label_author_and_subject' => tx_chcforum_shared::lang('form_label_author_and_subject'),
				'label_email' => tx_chcforum_shared::lang('form_label_email'),
				'label_subject' => tx_chcforum_shared::lang('form_label_subject'),
				'label_post' => tx_chcforum_shared::lang('form_label_post'),
				'form_help' => tx_chcforum_shared::lang('form_help'),
				'label_instruct' => tx_chcforum_shared::lang('form_label_instruct'),
				'b_help' => tx_chcforum_shared::lang('form_b_help'),
				'i_help' => tx_chcforum_shared::lang('form_i_help'),
				'u_help' => tx_chcforum_shared::lang('form_u_help'),
				'q_help' => tx_chcforum_shared::lang('form_q_help'),
				'c_help' => tx_chcforum_shared::lang('form_c_help'),
				'p_help' => tx_chcforum_shared::lang('form_p_help'),
				'w_help' => tx_chcforum_shared::lang('form_w_help'),
				'a_help' => tx_chcforum_shared::lang('form_a_help'),
				's_help' => tx_chcforum_shared::lang('form_s_help'),
				'f_help' => tx_chcforum_shared::lang('form_f_help'),
				'b_value' => tx_chcforum_shared::lang('form_b_value'),
				'i_value' => tx_chcforum_shared::lang('form_i_value'),
				'u_value' => tx_chcforum_shared::lang('form_u_value'),
				'q_value' => tx_chcforum_shared::lang('form_q_value'),
				'p_value' => tx_chcforum_shared::lang('form_p_value'),
				'w_value' => tx_chcforum_shared::lang('form_w_value'),
				'close_tags' => tx_chcforum_shared::lang('form_close_tags'),
				'missing_subject' => tx_chcforum_shared::lang('form_missing_subject'),
				'missing_message' => tx_chcforum_shared::lang('form_missing_message')
			);
			
			// Getting the current user information.
			$this->name = $display_object->name;
			$this->rawName = $display_object->rawName;
			$this->email = $display_object->email;	 

			// we prefer name to be the full name, but we'll settle for username if name isn't available.
			// if anonymous write access is allowed, the name can be anything, and we're not going to 
			// check it.
			if ($this->user->uid or $display_object->conference->conference_public_w == false) {
				if ($this->fconf['use_username'] == true) {
					$this->name = $this->user->username;
				} else {
					if ($this->user->name) {
						$this->name = $this->user->name;
					} else {
						if ($this->user->username) {
							$this->name = $this->user->username;
						}
					}
				}
			} else {
				
			}
			
			// set the user email -- why?
			if ($this->user->email) $this->email = $this->user->email;
			
			// set username and fe_user_uid -- why? 
			$this->username = $this->user->username;
			$this->fe_user_uid = $this->user->uid;
						 
			// Setting any vars that might have been sent via post.
			$this->view = $display_object->view;
			$this->cat_uid = $display_object->cat_uid;
			$this->conf_uid = $display_object->conf_uid;
			$this->thread_uid = $display_object->thread_uid;
			$this->post_uid = $display_object->post_uid;
			$this->where = $display_object->where;
			$this->preview = $display_object->preview;
			$this->subject = $display_object->subject;
			$this->rawSubject = $display_object->rawSubject;
			$this->cancel = $display_object->cancel;
			$this->text = $display_object->text;
			$this->rawText = $display_object->rawText;
			$this->submit = $display_object->submit;
			$this->flag = $display_object->flag;
			$this->page = $display_object->page;
			$this->attachment = $display_object->files['attachment'];
			$this->attach_file_name = $display_object->attach_file_name;
			$this->thread_endtime = $display_object->thread_endtime;
			
			// Check that the file was in fact uploaded.
			if ($this->attach_file_name) {
				$file_path = 'uploads/tx_chcforum/'.$this->attach_file_name;
				$uploadfile = t3lib_div::getFileAbsFileName($file_path);
				if (file_exists($uploadfile)) $this->file_was_uploaded = true;
			}
			
			// Set the stage for the form (not sure if I'm still using this...)
			if ($display_object->stage) {
				$this->stage = $display_object->stage;
			} else {
				$this->stage = 'new';
			}
			
			// If it we're quoting, add the quoted text to $this->text
			if ($this->flag == "quote" && $this->post_uid) {
				$tx_chcforum_post = t3lib_div::makeInstanceClassName("tx_chcforum_post");
				$quoted_post = new $tx_chcforum_post($this->post_uid, $this->cObj);
				$this->text = '[quote='.$quoted_post->post_author_name.']'.$quoted_post->post_text.'[/quote]';
			}
			 
			// If we're editing a post, make sure that the user is authorized to edit -- if so, fill in the form.
			if ($this->view == "edit_post" && $this->post_uid && $this->user->can_edit_post($this->post_uid) == true) {
				$tx_chcforum_message = t3lib_div::makeInstanceClassName("tx_chcforum_message");
				$this->message = new $tx_chcforum_message($this->cObj, tx_chcforum_shared::lang('edit_msg'), 'message');
				$tx_chcforum_post = t3lib_div::makeInstanceClassName("tx_chcforum_post");
				$edit_post = new $tx_chcforum_post($this->post_uid, $this->cObj);
				if (empty($this->subject)) $this->subject = $edit_post->post_subject;
				if (empty($this->text)) $this->text = $edit_post->post_text;
				$tx_chcforum_author= t3lib_div::makeInstanceClassName("tx_chcforum_author");
				$this->author = new $tx_chcforum_author($edit_post->post_author, $this->cObj);				
				if ($this->author->uid) {
					$this->name = $edit_post->post_author_name;
					$this->username = $this->author->username;
					$this->email = $edit_post->post_author_email;
				} else {
					$this->name = $edit_post->post_author_name; 
					$this->email = $edit_post->post_author_email;
					$this->username = $this->author->username;
					if (!$this->username) $this->username = tx_chcforum_shared::lang('guest');
				}
			}
			 
			// If the user can attach files, add the label to the label array
			if ($this->conf_uid && $this->user->can_attach_conf($this->conf_uid) == true && $this->view != 'edit_post') {
				$this->label_array['label_attachment'] = tx_chcforum_shared::lang('form_label_attachment');
			}

			// is the current conference set to hide new posts?
			if ($display_object->conference->hide_new == true) {
				$this->hide_new = true;
			}


			// Set up the emoticons
 			// Check if emoticons are disabled
 			if ($this->fconf['emoticons_disable'] == false) {
 				$emoticons = array();
 				// Load default emoticons if individual icons are empty or should be added to default icons
 				if (empty($this->fconf['emoticons_type']) || $this->fconf['emoticons_add']) {
 					// Define images and search codes
 					$emoticons = array(':arrow:' => 'arrow.gif',
  								     ':badgrin:' => 'badgrin.gif',
 										 	 ':D' => 'biggrin.gif',
 											 ':?' => 'confused.gif',
 											 '8-)' => 'cool.gif',
 											 ':(' => 'cry.gif',
 											 ':doubt:' => 'doubt.gif',
 											 '#evil#' => 'evil.gif',
 											 ':!:' => 'exclaim.gif',
 											 ':idea:' => 'idea.gif',
 											 '#giggle#' => 'lol.gif',
 											 ':mad:' => 'mad.gif',
 											 ':neutral:' => 'neutral.gif',
 											 ':question:' => 'question.gif',
 											 ':razz:' => 'razz.gif',
 											 ':o' => 'redface.gif',
 											 '#paralyzed#' => 'rolleyes.gif',
 											 ':(' => 'sad.gif',
 											 ':shock:' => 'shock.gif',
 											 ':)' => 'smile.gif',
 											 ':o' => 'surprised.gif',
 											 ';)' => 'wink.gif');
 				}
 				// Parse individual emoticons
 				if (!empty($this->fconf['emoticons_type'])) {
 					// Split fconf value in lines
 					$emicoValues = explode("\n", $this->fconf['emoticons_type']);
 					// Split lines in emoticon code and image name
 					reset($emicoValues);
 					while (list(, $emicoLine) = each($emicoValues)) {
 						$emicoTemp = explode(',', $emicoLine);
 						$emoticons[trim($emicoTemp[0])] = trim($emicoTemp[1]);
 					}
 				}

 				// Get emoticon path
 				$emicoPath =$this->fconf['emoticons_path'];

 				// Generate emoticon html image tags
 				reset($emoticons);
 				while (list($emicoKey, $emicoValue) = each($emoticons)) {
 					$this->emoticonCode .= $this->cObj->IMAGE(array('file' => $emicoPath.$emicoValue,
												  				'border' => '0',
 																	'alttext' => $this->pi_getLL('emoticons.'.$emicoValue, 'Emoticon'),
 																	'params' => 'class="tx-chcforum-pi1-formEmicoStyle" onclick="emoticon(\''.$emicoKey.'\')"'));
 				}
 			}
		}
		 
	 /**
		* Used to debug the form -- needs updating
		*
		* @return string  html table with debug information.
		*/
		function debug_form () {
			print '<table>';
			print '<tr><td>Name:</td><td>'.$this->name.'</td></tr>';
			print '<tr><td>Username:</td><td>'.$this->username.'</td></tr>';
			print '<tr><td>email:</td><td>'.$this->email.'</td></tr>';
			print '<tr><td>fe_user_uid:</td><td>'.$this->fe_user_uid.'</td></tr>';
			print '<tr><td>view:</td><td>'.$this->view.'</td></tr>';
			print '<tr><td>cat_uid:</td><td>'.$this->cat_uid.'</td></tr>';
			print '<tr><td>conf_uid:</td><td>'.$this->conf_uid.'</td></tr>';
			print '<tr><td>thread_uid:</td><td>'.$this->thread_uid.'</td></tr>';
			print '<tr><td>post_uid:</td><td>'.$this->post_uid.'</td></tr>';
			print '<tr><td>stage:</td><td>'.$this->stage.'</td></tr>';
			print '<tr><td>preview:</td><td>'.$this->preview.'</td></tr>';
			print '<tr><td>subject:</td><td>'.$this->subject.'</td></tr>';
			print '<tr><td>text:</td><td>'.$this->text.'</td></tr>';
			print '<tr><td>button:</td><td>'.$this->button.'</td></tr>';
			print '<tr><td>crdate:</td><td>'.$this->crdate.'</td></tr>';
			print '<tr><td>submit:</td><td>'.$this->submit.'</td></tr>';
			print '<tr><td>cancel:</td><td>'.$this->cancel.'</td></tr>';
			print '<tr><td>validated:</td><td>'.$this->validated.'</td></tr>';
			print '<tr><td>page:</td><td>'.$this->page.'</td></tr>';
			print '<tr><td>flag:</td><td>'.$this->flag.'</td></tr>';
			print '<tr><td>where:</td><td>'.$this->where.'</td></tr>';
			print '</table>';
		}
		 
	 /**
	  * Public interface for the form object. This is the only method that gets called
	  * outside of the class.
		*
		* @param boolean $debug set to true to debug the form submission / handling / validation / etc.
		* @return void
    */
		function handle_form($debug = false) {
			// If the incoming submit variable equals cancel, unset the form object completely.
			if ($this->cancel) {
				$this->reset_form();
				// if a file was uploaded, get rid of it
				$file_path = 'uploads/tx_chcforum/'.$this->attach_file_name;
				$uploadfile = t3lib_div::getFileAbsFileName($file_path);
				if (file_exists($uploadfile)) @unlink($uploadfile);
					$this->stage = 'new';
			}
			 
			// set crdate for the form object
			$this->crdate = time();
			if ($debug == true) $this->debug_form();
				 
			if ($this->stage) {
				if ($this->flag == 'delete') $this->process_delete_flag();
					switch ($this->stage) {
					// The form was submitted
					case 'previewed':
					// If it's valid, we can submit the post to the DB
					$this->validate();
					if ($this->validated == true) {
						// Submit post to DB
						$this->submit();

						// used solely for dev purposes
						if ($this->lorem_forum == true) {
							while ($this->lorem_forum_count <= $this->lorem_forum) {
								$this->submit();
								$this->lorem_forum_count++;
							}					
						}
						// end dev routine

					} else {
						// tell the user why it failed
						$this->errors();
					}
					break;
					case 'posted':

					//was a preview requested? If it was...
					if ($this->preview == 1) {
						// We need to validate it
						$this->validate();
						// It passed validation
						if ($this->validated == true) {
							// Display the requested preview
							$this->preview();
							// It failed validation
						} else {
							// tell the user why it failed
							$this->html_out .= $this->errors();
						}
						// no preview requested
					} else {
						// Looks like a preview was not requested. In that case, we need to validate it
						$this->validate();
						// If it's valid, we can submit the post to the DB
						if ($this->validated == true) {
							// Submit post to DB
							$this->submit();

							// used solely for dev purposes
							if ($this->lorem_forum == true) {
								while ($this->lorem_forum_count <= $this->lorem_forum) {
									$this->submit();
									$this->lorem_forum_count++;
								}					
							}
							// end dev routine
							
						} else {
							// tell the user why it failed
							$this->html_out .= $this->errors();
						}
					}
					break;
					case 'new':
					// First time pulling up the form -- display it. Set stage to posted first -- gets written into form HTML
					#$this->stage = 'posted';
					break;
					default:
					// First time pulling up the form -- display it.
					break;
				}
			}
			return $this->html_out;
		}
		 
	 /**
		* Display a preview of a post.
		*
		* @return void
		*/
		function preview() {
			$tx_chcforum_post = t3lib_div::makeInstanceClassName("tx_chcforum_post");
			$preview_post = new $tx_chcforum_post('', $this->cObj, true);
			$preview_post->preview = true;
			$preview_post->post_author_name = $this->name;
			$preview_post->post_subject = $this->subject;
			$preview_post->post_text = $this->text;
			$preview_post->crdate = $this->crdate;
			$preview_post->conf_auth = true;
			$tx_chcforum_message = t3lib_div::makeInstanceClassName("tx_chcforum_message");
			$preview_message = new $tx_chcforum_message($this->cObj, tx_chcforum_shared::lang('preview_message'), 'message');
			$this->html_out .= $preview_message->display();
			$this->html_out .= $preview_post->display_post();
			$this->stage = 'previewed';
			$this->is_preview = true;
		}
		 
	 /**
		* Resets the form vars. Used on cancel.
		*
		* @return void
		*/
		function reset_form() {
			unset($this->subject);
			unset($this->text);
			unset($this->thread_endtime);
			$this->stage = 'new';
			// if the view was single_post, and the reply has been submitted, we need to
			// go back to the single_thread view -- and we need to jump to the last page!
			if ($this->flag == 'delete') $this->view = 'single_conf';
			if ($this->view == 'single_post') $this->view = 'single_thread';
			if ($this->view == 'single_thread') $this->flag = 'last';
			if ($this->view == 'single_conf') $this->flag = 'first';
		}
		 
	 /**
		* Handles and outputs any errors from form submission / validation.
		*
		* @return void
		*/
		function errors() {
			if ($this->error) {
				$msg_txt .= tx_chcforum_shared::lang('validate_error_hdr');
				foreach ($this->error as $error) {
					$msg_txt .= $error.'<br />';
				}
				$tx_chcforum_message = t3lib_div::makeInstanceClassName("tx_chcforum_message");
				$message = new $tx_chcforum_message($this->cObj, $msg_txt, 'message');
				$out .= $message->display();
			}
			return $out;
		}
		 
	 /**
		* Form validation method.
		*
		* @return void
		*/
		function validate() {
			$this->validated = false;
                  // 05/07/07 Funktion function validate() (ca. Zeile 485) um folgende Zeilen erweitert:
                  if (t3lib_extMgm::isLoaded('captcha'))  {
                                session_start();
                                $captchaStr = $_SESSION['tx_captcha_string'];
                                $_SESSION['tx_captcha_string'] = '';
                        } else {
                                $captchaStr = -1;
                        }
                       
                        if($_POST['captcha'] != $captchaStr) {
                                $this->error['captcha'] = 'Please repeat the correct code!';
                        } else {
                                $valid_captcha = true;
                        }
			// make sure that we have a name, text, subject, and email address for the message.
			if (empty($this->name)) {
				$this->error['name'] = tx_chcforum_shared::lang('validate_name');
			} else {
				$valid_name = true;
			}
			if (empty($this->text)) {
				$this->error['text'] = tx_chcforum_shared::lang('validate_text');
			} else {
				$valid_text = true;
			}
			if (empty($this->subject)) {
				$this->error['subject'] = tx_chcforum_shared::lang('validate_subject');
			} else {
				$valid_subject = true;
			}
			if (empty($this->email)) {
				 // unless fconf is set to optional email, return error
				 if ($this->fconf['req_email'] != true) {
					 $this->error['email'] = tx_chcforum_shared::lang('validate_email');
				 } else {
				 	 $valid_email = true;
				 }
			} else {
				$valid_email = true;
			}
		
			// validate thread_endtime
			if ($this->fconf['allow_thread_endtime'] == 1 && $this->where == 'single_conf') {
				$thread_endtime = intval($this->thread_endtime);
				$max = $this->fconf['max_thread_lifetime'];
				if ($max > 0) {
					if ($thread_endtime > $max) $thread_endtime = $max;
				}
				if ($thread_endtime < 0) $thread_endtime = 0;
				$this->thread_endtime = $thread_endtime;
			} else {
				unset ($this->thread_endtime);
			}
			
			// if there's a default endtime, and now other value is set, set it.
			if ($this->fconf['thread_lifetime'] && !$this->thread_endtime) {
				$this->thread_endtime = intval($this->fconf['thread_lifetime']);
			}
			 
			// i'm not running further validation on these vars, since they should get validated
			// in display.
			if (!empty($this->cat_uid) && is_numeric($this->cat_uid)) $valid_catuid = true;
			if (!empty($this->conf_uid) && is_numeric($this->conf_uid)) $valid_confuid = true;

			// Attachment validation...
			if ($this->attachment && $this->attachment['name'] && $this->attachment['type'] && $this->attachment['tmp_name'] && $this->attachment['size'] && $this->attachment['error'] == 0) {

				$valid_attachment = false;
				// check the $tmp_name and $name path strings
				if (t3lib_div::validPathStr(t3lib_div::fixWindowsFilePath($this->attachment['tmp_name'])) == true ) {
					$valid_1 = true;
				} else {
					$this->error['attach_upload'] = tx_chcforum_shared::lang('validate_upload');
				}
				if (t3lib_div::validPathStr(t3lib_div::fixWindowsFilePath($this->attachment['name'])) == true ) {
					$valid_2 = true;
				} else {
					$this->error['attach_upload'] = tx_chcforum_shared::lang('validate_upload');
				}
				 
				// check the size
				if (!$this->fconf['max_attach']) $this->fconf['max_attach'] = (100 * 1024); // if we don't have a max size, set it to 100k
				if ($this->attachment['size'] <= ($this->fconf['max_attach'] * 1024)) {
					$valid_3 = true;
				} else {
					$this->error['attach_size'] = tx_chcforum_shared::lang('validate_size');
				}
				 
				// make sure it's uploaded
				if (is_uploaded_file($this->attachment['tmp_name']) == true) {
					$valid_4 = true;
				} else {
					$this->error['attach_upload'] = tx_chcforum_shared::lang('validate_upload');
				}
				 
				// check errors
				if ($this->attachment['error'] == 0) {
					$valid_5 = true;
				} else {
					$this->error['attach_upload'] = tx_chcforum_shared::lang('validate_upload');
				}
	 		 
				// check file extension -- get from fconf. Add any errors to $this->error['attachment']
				$extension = strtolower(substr(strrchr($this->attachment['name'], '.'), 1));
				$allowed = explode(',',strtolower($this->fconf['allowed_file_types']));
				if ($allowed) foreach ($allowed as $key=>$value) $allowed[$key]=trim($value);
				if (is_array($allowed) && in_array($extension, $allowed)) {
					$valid_6 = true;
				} else {
					$this->error['attach_type'] = tx_chcforum_shared::lang('validate_type');
				}

				// check mime type -- get from fconf.
				$mime = $this->attachment['type'];
				$allowed = explode(',',strtolower($this->fconf['allowed_mime_types']));
				if ($allowed) foreach ($allowed as $key=>$value) $allowed[$key]=trim($value);
				if (is_array($allowed) && in_array($mime, $allowed)) {
					$valid_7 = true;
				} else {
					$this->error['attach_type'] = tx_chcforum_shared::lang('validate_type');
				}
				 
				if ($valid_1 && $valid_2 && $valid_3 && $valid_4 && $valid_5 && $valid_6 && $valid_7) $valid_attachment = true;
			} else {
				// either no file was set, or the file that was sent was not valid, so we need to unset the attachment post.
				unset($this->attachment);
				$valid_attachment = true;
				$no_attachment = true;
			}
			 
			// we have to move the file here or else it will be deleted from the temporary location.
			if ($valid_attachment == true && !$this->attach_file_name && !$no_attachment) {
				$attach_file_name = $this->attachment['name'];
				$file_path = 'uploads/tx_chcforum/'.$attach_file_name;
				$uploadfile = t3lib_div::getFileAbsFileName($file_path);
				$tmp_file = t3lib_div::upload_to_tempfile($this->attachment['tmp_name']);
				 
				while (file_exists($uploadfile)) {
					$i++;
					$file_path = 'uploads/tx_chcforum/'.$i.$attach_file_name;
					$uploadfile = t3lib_div::getFileAbsFileName($file_path);
				}
				$this->attach_file_name = $i.$attach_file_name;
				 
				t3lib_div::upload_copy_move($tmp_file, $uploadfile);
				if (file_exists($uploadfile)) $this->file_was_uploaded = true;
				if ($tmp_file) t3lib_div::unlink_tempfile($tmp_file);
			}
			 
			if ($valid_name == true && $valid_text == true && $valid_subject == true && $valid_captcha == true && $valid_email == true && $valid_catuid == true && $valid_confuid == true && $valid_attachment == true) $this->validated = true;
			 
			// at this point, the post is generally valid...
			 
			// if we're in edit view and the user can't mod this conf, then we won't validate this post.
			if ($this->where == "edit_view" && $this->user->can_mod_conf($this->conf_uid) != true) $this->validated = false;
		}
		 
	 /** 
		* Method that creates HTML for the form. View is where the form is placed.
		*
		* @return void
		*/
		function display_form() {
			
			// decide what label to put at the top of the form, in the legend
			switch ($this->view) {
				case "single_conf":
					$this->label_array['label_where'] = tx_chcforum_shared::lang('form_label_where_conf');
				break;
				
				case "single_post":
					$this->label_array['label_where'] = tx_chcforum_shared::lang('form_label_where_post');
				break;

				case "edit_post":
					$this->label_array['label_where'] = tx_chcforum_shared::lang('form_label_where_edit');
				break;
				
				case "single_thread":
					$this->label_array['label_where'] = tx_chcforum_shared::lang('form_label_where_thread');
				break;				
				
				case "default":
					$this->label_array['label_where'] = tx_chcforum_shared::lang('form_label_where_default');					
				break;
			}

			// We're not doing anything if the user isn't authorized to view the conf in which
			// The form is being displayed.
			if ($this->conf_uid && $this->user->can_write_conf($this->conf_uid) == true) {
				// Set up Javascript
				if (!$this->tmpl_path) $this->tmpl_path = tx_chcforum_shared::setTemplatePath();
					$tx_chcforum_tpower = t3lib_div::makeInstanceClassName("tx_chcforum_tpower");
					$tmpl = new $tx_chcforum_tpower($this->tmpl_path.'post_form.js');
				$tmpl->prepare();
				$tmpl->assign($this->label_array);
				// Output Javascript
				$this->html_out .= $tmpl->getOutputContent();
				 
				// Set up HTML template
				if (!$this->tmpl_path) $this->tmpl_path = tx_chcforum_shared::setTemplatePath();
					$tx_chcforum_tpower = t3lib_div::makeInstanceClassName("tx_chcforum_tpower");
					$tmpl = new $tx_chcforum_tpower($this->tmpl_path.'post_form.tpl');
				$tmpl->prepare();
				$tmpl->assign($this->label_array);

				// Set form action.
				$tmpl->assign('action', $this->action);
				 
				// Decide what to put in the name and author field -- if there's a user logged in,
				// fill it in automatically. Otherwise render the input fields for username and email.
				if ($this->user->uid) {
					if ($this->fconf['use_username'] == true) {
						$tmpl->assign('username',$this->username);		
					} else {
						$tmpl->assign('name', $this->name);
						$tmpl->assign('username', '['.$this->username.']');
					}
					$tmpl->assign('email', $this->cObj->getTypoLink($this->email, $this->email));
				} else {
					if ($this->rawName) {
						$name = $this->rawName;
					} else {
						$name = $this->name;
					}
					$tmpl->assign('name', '<input type="text" maxlength="50" size="40" name="name" value="'.t3lib_div::htmlspecialchars_decode($name).'" />');
					$tmpl->assign('email', '<input type="text" maxlength="100" size="40" name="email" value="'.t3lib_div::htmlspecialchars_decode($this->email).'" />');
				}
				 
				// Stick all this info in here -- all the ids get validated anyways (and it isn't safe
				// to trust them anyhow, so they might be approaching unnecessary.
				$tmpl->assign('hash_fe_user_uid', tx_chcforum_shared::makeHash($this->fe_user_uid));
				$tmpl->assign('hash_cat_uid', tx_chcforum_shared::makeHash($this->cat_uid));
				$tmpl->assign('hash_conf_uid', tx_chcforum_shared::makeHash($this->conf_uid));
				$tmpl->assign('hash_thread_uid', tx_chcforum_shared::makeHash($this->thread_uid));
				$tmpl->assign('hash_post_uid', tx_chcforum_shared::makeHash($this->post_uid));
				$tmpl->assign('hash_view', tx_chcforum_shared::makeHash($this->view));
				$tmpl->assign('page', $this->page);
				$tmpl->assign('button', $this->button);
				$tmpl->assign('where', $this->where);

				// if posts in this conference are hidden until approved,
				// display a message to that effect.
				if ($this->hide_new == true) {
					$tx_chcforum_message = t3lib_div::makeInstanceClassName("tx_chcforum_message");
					$message = new $tx_chcforum_message($this->cObj, tx_chcforum_shared::lang('form_hide_new'), 'error');
					$tmpl->assign('message',$message->display());
				}		

 				// Assign emoticon code to template
				$tmpl->newBlock('emoticons');
 				$tmpl->assign('emoticons', $this->emoticonCode);
				$tmpl->gotoBlock('_ROOT');

				// Assign thread enddate code to template
				if ($this->fconf['allow_thread_endtime'] == 1 && $this->where == 'single_conf') {
					$tmpl->newBlock('thread_endtime');
					$tmpl->assign('label_endtime',tx_chcforum_shared::lang('form_label_endtime'));
					$tmpl->assign('endtime_inpt', '<input type="text" name="thread_endtime" value="'.$this->thread_endtime.'" size="5" />');
					if ($this->fconf['max_thread_lifetime']) {
						$max_str = tx_chcforum_shared::lang('form_label_max_endtime');
						$max_str = str_replace('###num###',$this->fconf['max_thread_lifetime'],$max_str);
						$tmpl->assign('label_max_endtime',$max_str);
					}
					$tmpl->gotoBlock('_ROOT');					
				}
				
				// set up paths for buttons
				$tmpl->assign('img_path', $this->fconf['tmpl_img_path']);
				
				// Set up the default subject for new posts.
				if (empty($this->subject) && $this->thread_uid) {
					$tx_chcforum_thread= t3lib_div::makeInstanceClassName("tx_chcforum_thread");
					$thread = new $tx_chcforum_thread($this->thread_uid, $this->cObj);
					$this->subject = tx_chcforum_shared::lang('reply_label').' '.$thread->thread_subject;
				}
				
				// If we already have data for subject or post, stick it in the fields (probably
				// means we're editing or previewing.
				// note that we have to decode everything that goes back in a form field (actually,
				// do we need this for subject field?)

				if ($this->rawText) { 
					$text = $this->rawText; 
				} else {
					$text = $this->text;
				}
				if ($this->rawSubject) { 
					$subject = $this->rawSubject; 
				} else {
					$subject = $this->subject;
				}
				

				$tmpl->assign('subject', $subject);
				$tmpl->assign('text', $text);
				
				// Stage tracking -- set the form stage correctly.
				if ($this->stage == "new" or $this->stage == 'previewed') {
					$tmpl_stage = 'posted';
					$tmpl->assign('stage', 'posted');
				} else {
					$tmpl_stage = $this->stage;
					$tmpl->assign('stage', $this->stage);
				}

				// setup post and preview buttons
				if ($this->view == 'edit_post') {
					$submit_btn_text = tx_chcforum_shared::lang('display_form_btn_edit');
				} else {
					$submit_btn_text = tx_chcforum_shared::lang('display_form_btn_post');
				}
				$tmpl->assign('submit', $submit_btn_text);
				$tmpl->assign('preview_btn', tx_chcforum_shared::lang('display_form_btn_preview'));

				// set up attachments and cancel button. behaviour depends on whether or not
				// we're previewing.
				if ($this->stage == 'previewed') {
					// previewing
					if ($this->user->can_attach_conf($this->conf_uid) == true) {
						if (!$this->attach_file_name) {
							// user can attach and no attachment has been added yet
							$tmpl->assign('attach_inpt', '<input type="file" name="attachment" size="45" />');
						} else {
							// user can attach and attachment was added -- carry it over
							if ($this->attachment['name']) $tmpl->assign('attach_inpt', $this->attachment['name']. '<input type="hidden" name="attach_file_name" value="'.$this->attach_file_name.'" />');
							if ($this->attach_file_name) $tmpl->assign('attach_inpt', $this->attach_file_name. '<input type="hidden" name="attach_file_name" value="'.$this->attach_file_name.'" />');
						}	
					}
					$tmpl->newBlock('cancel');
					$tmpl->assign('cancel_confirm', tx_chcforum_shared::lang('display_form_cancel_confirm'));
					$tmpl->assign('cancel', tx_chcforum_shared::lang('display_form_btn_cancel'));
				} else {
					// not previewing
					if ($this->user->can_attach_conf($this->conf_uid) == true && $this->view != 'edit_post') {
						// not previewing -- include attachment input
						$tmpl->assign('attach_inpt', '<input type="file" name="attachment" size="45" />');
					}
				}



				// Output HTML countent
				$this->html_out .= $tmpl->getOutputContent();
			} else {
				// didn't pass authorization -- output an error message.	 
				$message_text = tx_chcforum_shared::lang('error_no_user');
				$tx_chcforum_message = t3lib_div::makeInstanceClassName("tx_chcforum_message");
				$message = new $tx_chcforum_message($this->cObj, $message_text, 'error');
				$this->html_out = $message->display();
				
			}

			return $this->html_out;
		}
		 
		/**
		* Submits form data to the database -- called ONLY after validation is successful.
		*
		* @param boolean $update: set to true if we're updating rather than inserting.
		* @return void
		*/
		function submit($update = false) {
			// Is the user allowed to write to this conference?
			if ($this->user->can_write_conf($this->conf_uid) != true) return false;
			// Is this thread closed?			
			if (in_array($this->thread_uid, $this->user->closed_threads)) return false;

			// Constants for all queries
			// $pid = $GLOBALS['TSFE']->id; OLD METHOD
			$pid = $this->conf['pidList']; // new method
			switch ($this->where) {
				// if where equals single_conf, that means were posting a new $tx_chcforum_post while viewing a single conf -- so we need a new $tx_chcforum_post, and a new $tx_chcforum_thread.
				case 'single_conf':
				// Add the post to the post table
				$table = 'tx_chcforum_post';
				$field_list = 'category_id,
					conference_id,
					post_author,
					post_author_name,
					post_author_email,
					post_subject,
					post_author_ip,
					post_edit_tstamp,
					post_edit_count,
					post_attached,
					post_text,
					hidden';
				$dataArr = array();
				$dataArr['category_id'] = $this->cat_uid;
				$dataArr['conference_id'] = $this->conf_uid;
				$dataArr['post_author'] = $this->fe_user_uid;
				$dataArr['post_author_name'] = $this->name;
				$dataArr['post_author_email'] = $this->email;
				$dataArr['post_subject'] = $this->subject;
				$dataArr['post_author_ip'] = t3lib_div::getIndpEnv('REMOTE_ADDR');
				$dataArr['post_edit_tstamp'] = 0;
				$dataArr['post_edit_count'] = 0;
				if ($this->hide_new == true) $dataArr['hidden'] = 1;
				if ($this->file_was_uploaded == true) $dataArr['post_attached'] = $this->attach_file_name;
				$dataArr['post_text'] = $this->text;

				// Search for same author, same subject, same conf, same cat, less than five minutes ago
				// probably a mistaken double-submit
				if ($this->fe_user_uid && $this->cat_uid && $this->conf_uid) {
					$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 
										      "category_id=".$this->cat_uid.
										      " AND conference_id=".$this->conf_uid.
										      " AND post_author=".$this->fe_user_uid.
										      " AND post_subject='".mysql_escape_string($this->subject)."'".
										      " AND tstamp>".(time()-60*5));
				} elseif ($this->cat_uid && $this->conf_uid) {
					$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 
										      "category_id=".$this->cat_uid.
										      " AND conference_id=".$this->conf_uid.
										      " AND post_subject='".mysql_escape_string($this->subject)."'".
										      " AND tstamp>".(time()-60*5));
				}
				
				if ($GLOBALS['TYPO3_DB']->sql_num_rows($res)>0) {
				  break;
				} 

				$query = $this->cObj->DBgetInsert($table, $pid, $dataArr, $field_list);
				$GLOBALS['TYPO3_DB']->sql(TYPO3_db, $query);
				if ($GLOBALS['TYPO3_DB']->sql_error()) t3lib_div::debug(array($GLOBALS['TYPO3_DB']->sql_error(), $query));
					if ($GLOBALS['TYPO3_DB']->sql_affected_rows() > 0) $postid = $GLOBALS['TYPO3_DB']->sql_insert_id();
					 
				// Add a new $tx_chcforum_thread to the thread table
				$table = 'tx_chcforum_thread';
				$field_list = 'category_id,
					conference_id,
					thread_subject,
					thread_author,
					thread_datetime,
					thread_views,
					thread_replies,
					thread_firstpostid,
					thread_lastpostid,
					endtime,
					hidden';
				$dataArr = array();
				$dataArr['category_id'] = $this->cat_uid;
				$dataArr['conference_id'] = $this->conf_uid;
				$dataArr['thread_subject'] = $this->subject;
				$dataArr['thread_author'] = $this->fe_user_uid;
				$dataArr['thread_datetime'] = $this->crdate;
				$dataArr['thread_views'] = 0;
				$dataArr['thread_replies'] = 0;
				$dataArr['thread_firstpostid'] = $postid;
				$dataArr['thread_lastpostid'] = $postid;
				$dataArr['thread_lastposttstamp'] = time();
				
				// deal with endtime
				if ($this->thread_endtime) {
					$now = time();
					$add = $this->thread_endtime * 24 * 60 * 60; // 24 hours per day, 60 minutes per hour, 60 seconds per minute.
					$endtime = $now + $add;
				}
				$dataArr['endtime'] = $endtime;

				// deal with default endtime

				if ($this->hide_new == true) $dataArr['hidden'] = 1;
				$query = $this->cObj->DBgetInsert($table, $pid, $dataArr, $field_list);
				$GLOBALS['TYPO3_DB']->sql(TYPO3_db, $query);

				if ($GLOBALS['TYPO3_DB']->sql_error()) t3lib_div::debug(array($GLOBALS['TYPO3_DB']->sql_error(), $query));
					if ($GLOBALS['TYPO3_DB']->sql_affected_rows() > 0) $threadid = $GLOBALS['TYPO3_DB']->sql_insert_id();
				// Update the post with the thread_id number
				$table = 'tx_chcforum_post';
				$uid = $postid;
				$field_list = 'thread_id';
				$dataArr['thread_id'] = $threadid;
				$query = $this->cObj->DBgetUpdate($table, $uid, $dataArr, $field_list);
				$GLOBALS['TYPO3_DB']->sql(TYPO3_db, $query);
				if ($GLOBALS['TYPO3_DB']->sql_error()) t3lib_div::debug(array($GLOBALS['TYPO3_DB']->sql_error(), $query));
				
				// consider the new post read by the current user.
				if ($this->user->uid && $postid) {
					$this->user->add_post_read($postid);
				}
				break;
				 
				// If we're posting in a thread that has already been created, then we're posting
				// a reply, and we don't need to add a thread to the thread table (although we do
				// need to update it.
				case 'single_thread':
				case 'single_post':
				// Add the post to the post table
				$table = 'tx_chcforum_post';
				$field_list = 'category_id,
					conference_id,
					thread_id,
					post_author,
					post_subject,
					post_author_ip,
					post_edit_tstamp,
					post_edit_count,
					post_attached,
					post_text,
					post_author_name,
					post_author_email,
					hidden';
				$dataArr = array();
				$dataArr['category_id'] = $this->cat_uid;
				$dataArr['conference_id'] = $this->conf_uid;
				$dataArr['thread_id'] = $this->thread_uid;
				$dataArr['post_author'] = $this->fe_user_uid;
				$dataArr['post_subject'] = $this->subject;
				$dataArr['post_author_ip'] = t3lib_div::getIndpEnv('REMOTE_ADDR');
				$dataArr['post_edit_tstamp'] = 0;
				$dataArr['post_edit_count'] = 0;
				if ($this->file_was_uploaded == true) $dataArr['post_attached'] = $this->attach_file_name;
				$dataArr['post_text'] = $this->text;
				$dataArr['post_author_name'] = $this->name;
				$dataArr['post_author_email'] = $this->email;
				if ($this->hide_new == true) $dataArr['hidden'] = 1;

				// Search for same author, same text, same conf, same cat, less than five minutes ago
				// probably a mistaken double-submit		
				// why the lorem_forum check? Lorem_forum allows you to save a single post to the database
				// hundreds or thousands of times (for testing purposes), so it's important to not check
				// for dupes if we're adding a bunch of test messages.
				if (!$this->lorem_forum) {
						$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 
									      	"category_id='".$this->cat_uid.
									      	"' AND conference_id='".$this->conf_uid.
									      	"' AND thread_id='".$this->thread_uid.
									      	"' AND post_author='".$this->fe_user_uid.
									      	"' AND post_text='".mysql_escape_string($this->text)."'".
 									      	" AND tstamp>".(time()-60*5));
					if ($GLOBALS['TYPO3_DB']->sql_num_rows($res)>0) {
				  	break;
					}
				}

				$query = $this->cObj->DBgetInsert($table, $pid, $dataArr, $field_list);
				$GLOBALS['TYPO3_DB']->sql(TYPO3_db, $query);
				if ($GLOBALS['TYPO3_DB']->sql_error()) t3lib_div::debug(array($GLOBALS['TYPO3_DB']->sql_error(), $query));
					if ($GLOBALS['TYPO3_DB']->sql_affected_rows() > 0) $postid = $GLOBALS['TYPO3_DB']->sql_insert_id();
					 
				// Update the thread with the post id number and a tstamp
				$table = 'tx_chcforum_thread';
				$uid = $this->thread_uid;
				$field_list = 'thread_lastpostid';
				$dataArr['thread_lastpostid'] = $postid;
				$query = $this->cObj->DBgetUpdate($table, $uid, $dataArr, $field_list);
				$GLOBALS['TYPO3_DB']->sql(TYPO3_db, $query);
				if ($GLOBALS['TYPO3_DB']->sql_error()) t3lib_div::debug(array($GLOBALS['TYPO3_DB']->sql_error(), $query));
					break;
				 
				// Used to update an edited post in the DB.
				case 'edit_post':
				// Update the post in the post table
				$table = 'tx_chcforum_post';
				$uid = $this->post_uid;
				$field_list = 'post_subject,post_edit_tstamp,post_text,post_edit_count';
				$dataArr = array();
				$dataArr['post_subject'] = $this->subject;
				$dataArr['post_edit_tstamp'] = time();
				$dataArr['post_text'] = $this->text;
				$dataArr['post_edit_count'] = 1; // fix this!
				$query = $this->cObj->DBgetUpdate($table, $uid, $dataArr, $field_list);
				$GLOBALS['TYPO3_DB']->sql(TYPO3_db, $query);
								
				if ($GLOBALS['TYPO3_DB']->sql_error()) debug(array($GLOBALS['TYPO3_DB']->sql_error(), $query));
					break;
			}
			
			if ($this->lorem_forum) {
				if ($this->lorem_forum_count == $this->lorem_forum) $this->reset_form();
			} else {
				$this->reset_form();				
			}
			
			$tx_chcforum_message = t3lib_div::makeInstanceClassName("tx_chcforum_message");
			$this->message = new $tx_chcforum_message($this->cObj, tx_chcforum_shared::lang('form_submitted'), 'message');

		}

	 /**
		* Prune the forum. This can be called without instantiating the form object, if need be.
	  * This is currently not used -- someday, it might get enabled. But it needs to be completed.
	  * Currently, this function only deletes the posts -- doesn't get rid of empty threads.
	  * It's also not tested.
		* @return void
		*/
		function prune() {
			$age = $this->fconf['pruning_age'];
			$fconf_age = $age['pruning_age']; // age in days
			if ($fconf_age > 0) {
				#$fconf_age_s = $fconf_age * 86400; // age in secs
				$fconf_age_s = $fconf_age * 16400; // age in secs
				$now = time(); // um...now
				$min_tstamp = $now - $fconf_age_s; // min tstamp value; anything less gets deleted
				$p_res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'tx_chcforum_post', "tstamp < $min_tstamp", '', '');
				if ($p_res) {
					while ($post = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($p_res)) {
						$posts_to_prune[] = array( 'uid' => $post['uid']);
					}
					$where = 'uid=\''.$posts_to_prune[0]['uid'].'\'';
					for ($key = 1, $size = count($posts_to_prune); $key < $size; $key++) {
						$where .= ' OR uid='.$posts_to_prune[$key]['uid'];
					}
					if ($where) $p_res = $GLOBALS['TYPO3_DB']->exec_DELETEquery('tx_chcforum_post', $where);
				}
			}
		}
		 
		/**
		* Processes any command to delete a message (sent via delete flag). Note -- security check performed
		* again here.
		*
		* @return void
		*/
		function process_delete_flag() {
			
			if ($this->post_uid && $this->user->can_mod_conf($this->conf_uid) == true) {
				// Update "deleted" to 1 in the post table
				$table = 'tx_chcforum_post';
				$uid = $this->post_uid;
				$field_list = 'deleted';
				$dataArr['deleted'] = 1;
				$query = $this->cObj->DBgetUpdate($table, $uid, $dataArr, $field_list);
				$GLOBALS['TYPO3_DB']->sql(TYPO3_db, $query);
				if ($GLOBALS['TYPO3_DB']->sql_error()) debug(array($GLOBALS['TYPO3_DB']->sql_error(), $query));
					unset($field_list);
				 
				// After deleting the message, check to see if there are any messages left in the
				// thread. If there aren't any remaining messages, you need to delete the thread, too.
				$tx_chcforum_thread= t3lib_div::makeInstanceClassName("tx_chcforum_thread");
				$thread = new $tx_chcforum_thread($this->thread_uid, $this->cObj);
				$table = 'tx_chcforum_thread';
				$uid = $thread->uid;
				 
				if ($thread->thread_lastpostid == $this->post_uid) {
					$lastpostid = $thread->return_most_recent_post();
					$dataArr['thread_lastpostid'] = $lastpostid;
					$field_list = 'thread_lastpostid';
					$query = $this->cObj->DBgetUpdate($table, $uid, $dataArr, $field_list);
					$GLOBALS['TYPO3_DB']->sql(TYPO3_db, $query);
					if ($GLOBALS['TYPO3_DB']->sql_error()) t3lib_div::debug(array($GLOBALS['TYPO3_DB']->sql_error(), $query));
					}
				 
				if ($thread->return_post_count() <= 0) {
					$field_list = 'deleted';
					$dataArr['deleted'] = 1;
					$query = $this->cObj->DBgetUpdate($table, $uid, $dataArr, $field_list);
					$GLOBALS['TYPO3_DB']->sql(TYPO3_db, $query);
					
					// we just deleted a thread, and we want to make sure
					// we don't return to it.
					$this->thread_deleted = true;
					unset($this->thread_uid);
					$this->view = 'single_conf';
					
					if ($GLOBALS['TYPO3_DB']->sql_error()) t3lib_div::debug(array($GLOBALS['TYPO3_DB']->sql_error(), $query));
						$this->reset_form();
				}
			}
		}
	}
	 
	if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/chc_forum/pi1/class.tx_chcforum_form.php']) {
		include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/chc_forum/pi1/class.tx_chcforum_form.php']);
	}
	
	
	 
?>

und die Datei /ext/chc_forum/pi1/templates/post_form.tpl
sieht so aus:

<form action="{action}" enctype="multipart/form-data" id="post" name="post" method="post" onsubmit="return checkForm(this)" class="tx-chcforum-pi1-postForm">
	{message}
	<input type="hidden" name="view" value="{hash_view}" />
	<input type="hidden" name="fe_user_uid" value="{hash_fe_user_uid}" />
	<input type="hidden" name="page" value="{page}" />
	<input type="hidden" name="post_uid" value="{hash_post_uid}" />
	<input type="hidden" name="thread_uid" value="{hash_thread_uid}" />
	<input type="hidden" name="conf_uid" value="{hash_conf_uid}" />
	<input type="hidden" name="cat_uid" value="{hash_cat_uid}" />
	<input type="hidden" name="where" value="{where}" />
	<input type="hidden" name="stage" value="{stage}" />
<div id="formWhere">{label_where}</div>
<fieldset id="formTop">
	<legend>&nbsp;{label_author_and_subject}&nbsp;</legend>
	<label for="name">{label_name}</label>
	{name} {username}<br />
	<label for="email">{label_email}</label>
	{email}<br />
	<label for="subject">{label_subject}</label>
	<input type="text" name="subject" size="40" value="{subject}" /><br style="clear: both" />
</fieldset>

<fieldset id="formBottom">
	<legend>&nbsp;{label_instruct}&nbsp;</legend>
	<img src="{img_path}bold_large.png" accesskey="b" name="addfcode0" value=" B " onclick="fcstyle(0)" onmouseover="helpline('b');"/>
	<img src="{img_path}italic_large.png" accesskey="i" name="addfcode2" value=" i " onclick="fcstyle(2)" onmouseover="helpline('i');"/>
	<img src="{img_path}underline_large.png" accesskey="u" name="addfcode4" value=" u " onclick="fcstyle(4)" onmouseover="helpline('u');"/>
	<img src="{img_path}color_large.png" accesskey="c" name="addfcode5" value=" c " onclick="fcstyle(12)" onmouseover="helpline('c');"/>
	<img src="{img_path}quote_large.png" accesskey="q" name="addfcode6" value="Quote" onclick="fcstyle(6)" onmouseover="helpline('q');"/>
	<img src="{img_path}image_large.png" accesskey="p" name="addfcode8" value="Img" onclick="fcstyle(8-)" onmouseover="helpline('p');"/>
	<img src="{img_path}url_large.png" accesskey="w" name="addfcode10" value="URL" onclick="fcstyle(10)" onmouseover="helpline('w');"/>
	<span><a href="javascript:fcstyle(-1)" onmouseover="helpline('a')" title="{close_tags}"><img style="border: 0px;" alt="{close_tags}" src="{img_path}close.png" /></a></span>
<br />
<input type="text" disabled="disabled" name="helpbox" size="45" maxlength="100" style="width:450px; font-size:10px" class="tx-chcforum-pi1-helpBox" value="{form_help}" />
<!-- START BLOCK : emoticons -->
<hr />
{emoticons}
<!-- END BLOCK : emoticons -->
<textarea name="text" rows="15" cols="35" onselect="storeCaret(this);" onclick="storeCaret(this);" onkeyup="storeCaret(this);" style="width:97%">{text}</textarea>
<!-- START BLOCK : thread_endtime -->
{label_endtime} {endtime_inpt} {label_max_endtime}
<hr />
<!-- END BLOCK : thread_endtime -->
{label_attachment} {attach_inpt}<br />
<hr />
Repeat code: *<input type="text" size="30" name="captcha" value="" />
{label_captcha}
<div class="tx-chcforum-pi1-formBtn"><input type="submit" name="submit" value="{submit}" onmouseover="this.className='tx-chcforum-pi1-formBtnHov'" onmouseout="this.className='tx-chcforum-pi1-formBtn'"/>
<input type="submit" name="preview" value="{preview_btn}" onmouseover="this.className='tx-chcforum-pi1-formBtnHov'" onmouseout="this.className='tx-chcforum-pi1-formBtn'"/></div>
<!-- START BLOCK : cancel -->
<div class="tx-chcforum-pi1-formBtn"><input type="submit" name="cancel" value="{cancel}" onmouseover="this.className='tx-chcforum-pi1-formBtnHov'" onmouseout="this.className='tx-chcforum-pi1-formBtn'" onclick="return(confirm('{cancel_confirm}'))"/></div>
<!-- END BLOCK : cancel -->
</fieldset>
</form>

Funktioniert nun wunderbar. Vielen Dank.

nicolaibassdh ·

WICHTIGER HINWEIS!!!

Der von mir im ersten Teil angezeigte Code für die Datei captcha.php ist nicht ganz vollständig, hier der korrekte und vollständige Code:

<?php
session_start();
function strrand($length)
{
	$str = "";

	while(strlen($str)<$length){
	$random=rand(48,122);
	#if( ($random>47 && $random<58-)  ){
	if (ereg('[A-Za-z]',chr($random)))
		$str.=chr($random);
	#}

	}

	return $str;
}

$imgHeight = 20;
$imgWidth = 50;

$text = $_SESSION['tx_captcha_string'] = strrand(5);
$img_number = imagecreate($imgWidth,$imgHeight);
$backcolor = imagecolorallocate($img_number,244,244,244);
$textcolor = imagecolorallocate($img_number,0,0,0);
$white = imagecolorallocate($img_number, 0xFF, 0xFF, 0xFF);

imagefill($img_number,0,0,$backcolor);

Imagestring($img_number,5,1,1,$text,$textcolor);

        //some obfuscation
        for ($i=0; $i<2; $i++) {
            $x1 = rand(0, $imgWidth - 1);
            $y1 = rand(0, round($imgHeight / 10, 0));
            $x2 = rand(0, round($imgWidth / 10, 0));
            $y2 = rand(0, $imgHeight - 1);
            imageline($img_number, $x1, $y1, $x2, $y2, $white);

			$x1 = rand(0, $imgWidth - 1);
            $y1 = $imgHeight - rand(1, round($imgHeight / 10, 0));
            $x2 = $imgWidth - rand(1, round($imgWidth / 10, 0));
            $y2 = rand(0, $imgHeight - 1);
            imageline($img_number, $x1, $y1, $x2, $y2, $white);
    }


header("Content-type: image/png");
imagepng($img_number);
?>

Besten Dank an latschma der mich hierauf hinwiesen hat 🙂

latschma ·

Funktioniert mit der captcha.php von nicolaibassdh genausogut. Vielen Dank.

Noch eine kleine Richtigstellung; der Pfad ist richtig:
/ext/chc_forum/pi1/class.tx_chcforum_form.php

latschma ·

Wichtig:

Das captcha von Bernhard Kraft verträgt sich NICHT mit "Flexform based IFrame ffiframe 1.1.0". Captcha wird nicht dargestellt und bei direkter Ansteuerung über http://domain.tld/typo3_src/typo3conf/ext/captcha/captcha/captcha.php gibt es diese Fehlermeldung:

Warning: Cannot modify header information - headers already sent by (output started at /share/storage/01/ff/name/typo3_src/typo3conf/ext/ffiframe/ext_localconf.php:18-) in /share/storage/01/ff/name/typo3_src/typo3conf/ext/captcha/captcha/captcha.php on line 193
‰PNG &#65533;&#65533;&#65533; IHDR&#65533;&#65533;&#65533;_&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;`“¶&#65533;&#65533;&#65533;9PLTE3™Ì&#65533;&#65533;&#65533;ÀÀÀ&#65533;&#65533;&#65533;3™Ì&3Lf,…²¨¨¨xxxHHH```000_&r™9L÷ êP&#65533;&#65533;ùIDATH‰­T‰’¬ ¤H\¢øÿ» ÇÝWó–ª)H:îˆ_,‰ë›¼Ìj•£¿Ç]Ôù?èïcÞ_z¹·—áu%€ðgäÇBs‰&ü%ø>e®t™ œ°ø+æBèt®»\”`A)‰_J¥7Ã!òëÛ yˆlp2ühQ1È%xÚ úAö–¹(`ྔÎS :4€\<*C]]OgÒåÕ¹Ú¿NFÌúd;€ïð# ÅNóÁ&#65533;˜ó¸µL@g$€Í pˆ¢ m‡ HŸw™º §.S³Ê‘¾2³Åßa–ÔÞA©¶[ã5bo8຦[PÅ¿\;Î\¦ùoä‡m²¤k å!=Îò z‘ê_djMh‹ãüLCbˆlß§ƒ˜¯O8îdS^ðOA›Þ¬>UåC ÛêLµ ±?ô[dϵIùØíÃ0P¶×Ér-PÓu`^ðePÄô:Zô

Es hilft nur die Deinstallation über das Backend.

Das normale captcha funktioniert in diesem Fall.

Grüße

steffenk ·

Das ist aber ein Fehler der "Flexform based IFrame ffiframe 1.1.0"

Wie die Fehlermeldung besagt, erfolgt hier eine Ausgabe. Da mir ansonsten keinerlei Unverträglichkeiten bekannt sind, würde ich die mal untersuchen.

Was steht bei der denn in der ext_localconf.php, Zeile 18?

latschma ·
steffenk schrieb

Das ist aber ein Fehler der "Flexform based IFrame ffiframe 1.1.0"
Was steht bei der denn in der ext_localconf.php, Zeile 18?

Da gibt es nur 15 Zeilen, wobei die zweite Zeile von mir eingefügt ist:

<?php
ini_set("max_execution_time", "200");
if (!defined ('TYPO3_MODE')) 	die ('Access denied.');

t3lib_extMgm::addUserTSConfig('
	options.saveDocNew.tx_ffiframe=1
');

  ## Extending TypoScript from static template uid=43 to set up userdefined tag:
t3lib_extMgm::addTypoScript($_EXTKEY,'editorcfg','
	tt_content.CSS_editor.ch.tx_ffiframe_pi1 = < plugin.tx_ffiframe_pi1.CSS_editor
',43);

t3lib_extMgm::addPItoST43($_EXTKEY,'pi1/class.tx_ffiframe_pi1.php','_pi1','list_type',1);
?>

Grüße

steffenk ·

dann hast Du Extra-Zeichen hinter dem ?> - je nach Editor kann das passieren, und es passt zu der Fehlermeldung.

latschma ·

Das wars dann auch schon. Drei leere Zeilen entfernt (CrimsonEditor zeigt die nicht an).
Jetzt geht es mit beiden zusammen.
Vielen Dank. :o

latschma ·

So, jetzt haben die Spammer angefangen manuell saftige Beiträge ins Forum zu schreiben. Das lässt sich bei mir auf IPs in China eingrenzen (haben die nichts anderes zu tun?).

Bei dem ISP geht es leider nicht mit .htaccess die Ausführung von php-Skripten zu verhindern. Man kann das Ausführen von php-Skripten nicht mit .htaccess verhindern, da es auf cgi läuft.

Gibt es eine Methode IPs, IP-ranges und domains via php-Skripts im CHC-forum auszusperren?

Danke.

latschma ·

Hallo

Kann das inzwischen Dank Hilfe beantworten.

Code am Ende der Haupttemplate einfuegen:

[IP = boese.ip1*.*.*, boese.ip2*.*.*] || [hostname = boeserhost1.com, boeserhost2.com]
  page {
    # redirect to external URL
    headerData.10 = TEXT
    headerData.10.value = <META http-equiv=Refresh Content="0; Url=http://www.goaway.com">
  }
[GLOBAL]

Oder, im .htaccess ein redirect einbauen, das wird bei meinem ISP unterstützt.
Code:

RewriteCond %{REMOTE_ADDR} ^boese.ip1*.*.*|boese.ip2*.*.*
RewriteCond %{HTTP_HOST} !^$
RewriteRule /* http://www.goaway.com/ [R,L]

Bleibe aber bei der TypoScript solution.

Nehme an, dass das nur was fuer kleine Seiten ist. Auf grossen Seiten gibt es dann vielleicht bald hunderte Eintraege die dann Verwaltet werden muessen. Waere das etwas fuer eine TYPO3 Extension? Nehme an, das wird sowieso auf grossen Seiten mit .htaccess oder Apache modulen erledigt??

Gruesse
latschma

latschma ·

Hallo nochmal ...

Gibt es eine Möglichkeit bestimmte Wörter zu indexieren, also dass ein Beitrag im Chc-Forum nicht veröffentlicht wird wenn die im Text sind?

Danke

latschma ·

Hallo

Habe jetzt nochmal das alles durchgelesen, aber die Forum-Spammer sind in der Lage pro Stunde manuell in 400 Foren Einträge zu machen (CAPTCHA sinnlos). Die einzige Möglichket wäre eine Liste mit blockierten Wörtern zu haben. Wer weiss wie, oder wer kann sowas in das CHC-Forum zu inkludieren.

Danke nochmal