*/ /** * [CLASS/FUNCTION INDEX of SCRIPT] * * * * 132: class user_feAdmin * 179: function init($content,$conf) * * SECTION: Data processing * 408: function parseValues() * 503: function processFiles($cmdParts,$theField) * 609: function overrideValues() * 625: function defaultValues() * 644: function evalValues() * 766: function userProcess($mConfKey,$passVar) * 784: function userProcess_alt($confVal,$confArr,$passVar) * * SECTION: Database manipulation functions * 826: function save() * 884: function deleteRecord() * 914: function deleteFilesFromRecord($uid) * * SECTION: Command "display" functions * 971: function displayDeleteScreen() * 999: function displayCreateScreen() * 1022: function displayEditScreen() * 1073: function displayEditForm($origArr) * 1101: function procesSetFixed() * * SECTION: Template processing functions * 1190: function removeRequired($templateCode,$failure) * 1208: function getPlainTemplate($key,$r='') * 1225: function modifyDataArrForFormUpdate($inputArr) * 1294: function setCObjects($templateCode,$currentArr=array(),$markerArray='',$specialPrefix='') * * SECTION: Emailing * 1356: function sendInfoMail() * 1404: function compileMail($key, $DBrows, $recipient, $setFixedConfig=array()) * 1450: function sendMail($recipient, $admin, $content='', $adminContent='') * 1495: function isHTMLContent($c) * 1516: function sendHTMLMail($content,$recipient,$dummy,$fromEmail,$fromName,$replyTo='') * * SECTION: Various helper functions * 1600: function aCAuth($r) * 1614: function authCode($r,$extra='') * 1640: function setfixed($markerArray, $setfixed, $r) * 1678: function setfixedHash($recCopy,$fields='') * 1699: function isPreview() * 1708: function createFileFuncObj() * 1719: function clearCacheIfSet() * 1734: function getFailure($theField, $theCmd, $label) * * TOTAL FUNCTIONS: 33 * (This index is automatically created/updated by the extension "extdeveval") * */ require_once (PATH_t3lib.'class.t3lib_basicfilefunc.php'); // For use with images. /** * This library provides a HTML-template file based framework for Front End creating/editing/deleting records authenticated by email or fe_user login. * It is used in the extensions "direct_mail_subscription" and "feuser_admin" (and the depreciated(!) static template "plugin.feadmin.dmailsubscription" and "plugin.feadmin.fe_users" which are the old versions of these two extensions) * Further the extensions "t3consultancies" and "t3references" also uses this library but contrary to the "direct_mail_subscription" and "feuser_admin" extensions which relies on external HTML templates which must be adapted these two extensions delivers the HTML template code from inside. * Generally the fe_adminLib appears to be hard to use. Personally I feel turned off by all the template-file work involved and since it is very feature rich (and for that sake pretty stable!) there are lots of things that can go wrong - you feel. Therefore I like the concept used by "t3consultancies"/"t3references" since those extensions uses the library by supplying the HTML-template code automatically. * Suggestions for improvement and streamlining is welcome so this powerful class could be used more and effectively. * * @author Kasper Skaarhoj * @package TYPO3 * @subpackage tslib * @link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&tx_extrepmgm_pi1[tocEl]=396&cHash=d267c36546 */ class user_feAdmin { // External, static: var $recInMarkersHSC = TRUE; // If true, values from the record put into markers going out into HTML will be passed through htmlspecialchars()! var $dataArr = array(); var $failureMsg = array(); var $theTable = ''; var $thePid = 0; var $markerArray = array(); var $templateCode=''; var $cObj; var $cmd; var $preview; var $backURL; var $recUid; var $failure=0; // is set if data did not have the required fields set. var $error=''; var $saved=0; // is set if data is saved var $requiredArr; var $currentArr = array(); var $previewLabel=''; var $nc = ''; // '&no_cache=1' if you want that parameter sent. var $additionalUpdateFields=''; var $emailMarkPrefix = 'EMAIL_TEMPLATE_'; var $codeLength; var $cmdKey; var $fileFunc=''; // Set to a basic_filefunc object var $filesStoredInUploadFolders=array(); // This array will hold the names of files transferred to the uploads/* folder if any. If the records are NOT saved, these files should be deleted!! Currently this is not working! // Internal vars, dynamic: var $unlinkTempFiles = array(); // Is loaded with all temporary filenames used for upload which should be deleted before exit... /** * Main function. Called from TypoScript. * This * - initializes internal variables, * - fills in the markerArray with default substitution string * - saves/emails if such commands are sent * - calls functions for display of the screen for editing/creation/deletion etc. * * @param string Empty string, ignore. * @param array TypoScript properties following the USER_INT object which uses this library * @return string HTML content * @link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&tx_extrepmgm_pi1[tocEl]=396&cHash=d267c36546 */ function init($content,$conf) { $this->conf = $conf; // template file is fetched. $this->templateCode = $this->conf['templateContent'] ? $this->conf['templateContent'] : $this->cObj->fileResource($this->conf['templateFile']); // Getting the cmd var $this->cmd = (string)t3lib_div::_GP('cmd'); // Getting the preview var $this->preview = (string)t3lib_div::_GP('preview'); // backURL is a given URL to return to when login is performed $this->backURL = t3lib_div::_GP('backURL'); // Uid to edit: $this->recUid = t3lib_div::_GP('rU'); // Authentication code: $this->authCode = t3lib_div::_GP('aC'); // get table $this->theTable = $this->conf['table']; $this->nc = $this->conf['no_cache'] ? '&no_cache=1' : $this->nc; // pid $this->thePid = intval($this->conf['pid']) ? intval($this->conf['pid']) : $GLOBALS['TSFE']->id; // $this->codeLength = intval($this->conf['authcodeFields.']['codeLength']) ? intval($this->conf['authcodeFields.']['codeLength']) : 8; // Setting the hardcoded lists of fields allowed for editing and creation. $this->fieldList=implode(',',t3lib_div::trimExplode(',',$GLOBALS['TCA'][$this->theTable]['feInterface']['fe_admin_fieldList'],1)); // globally substituted markers, fonts and colors. $splitMark = md5(microtime()); list($this->markerArray['###GW1B###'],$this->markerArray['###GW1E###']) = explode($splitMark,$this->cObj->stdWrap($splitMark,$this->conf['wrap1.'])); list($this->markerArray['###GW2B###'],$this->markerArray['###GW2E###']) = explode($splitMark,$this->cObj->stdWrap($splitMark,$this->conf['wrap2.'])); $this->markerArray['###GC1###'] = $this->cObj->stdWrap($this->conf['color1'],$this->conf['color1.']); $this->markerArray['###GC2###'] = $this->cObj->stdWrap($this->conf['color2'],$this->conf['color2.']); $this->markerArray['###GC3###'] = $this->cObj->stdWrap($this->conf['color3'],$this->conf['color3.']); // Initialize markerArray, setting FORM_URL and HIDDENFIELDS $this->markerArray['###FORM_URL###'] = 'index.php?id='.$GLOBALS['TSFE']->id.'&type='.$GLOBALS['TSFE']->type.$this->nc.$this->conf['addParams']; $this->markerArray['###FORM_URL_ENC###'] = rawurlencode($this->markerArray['###FORM_URL###']); $this->markerArray['###FORM_URL_HSC###'] = htmlspecialchars($this->markerArray['###FORM_URL###']); $this->markerArray['###BACK_URL###'] = $this->backURL; $this->markerArray['###BACK_URL_ENC###'] = rawurlencode($this->markerArray['###BACK_URL###']); $this->markerArray['###BACK_URL_HSC###'] = htmlspecialchars($this->markerArray['###BACK_URL###']); $this->markerArray['###THE_PID###'] = $this->thePid; $this->markerArray['###REC_UID###'] = $this->recUid; $this->markerArray['###AUTH_CODE###'] = $this->authCode; $this->markerArray['###THIS_ID###'] = $GLOBALS['TSFE']->id; $this->markerArray['###THIS_URL###'] = htmlspecialchars(t3lib_div::getIndpEnv('TYPO3_REQUEST_DIR')); $this->markerArray['###HIDDENFIELDS###'] = ($this->cmd?'':''). ($this->authCode?'':''). ($this->backURL?'':''); // Setting cmdKey which is either 'edit' or 'create' switch($this->cmd) { case 'edit': $this->cmdKey='edit'; break; default: $this->cmdKey='create'; break; } // Setting requiredArr to the fields in 'required' intersected field the total field list in order to remove invalid fields. $this->requiredArr = array_intersect( t3lib_div::trimExplode(',',$this->conf[$this->cmdKey.'.']['required'],1), t3lib_div::trimExplode(',',$this->conf[$this->cmdKey.'.']['fields'],1) ); // Setting incoming data. Non-stripped $fe=t3lib_div::_GP('FE'); $this->dataArr = $fe[$this->theTable]; // Incoming data. // Checking template file and table value if (!$this->templateCode) { $content = 'No template file found: '.$this->conf['templateFile']; return $content; } if (!$this->theTable || !$this->fieldList) { $content = 'Wrong table: '.$this->theTable; return $content; // Not listed or editable table! } // ***************** // If data is submitted, we take care of it here. // ******************* if ($this->cmd=='delete' && !$this->preview && !t3lib_div::_GP('doNotSave')) { // Delete record if delete command is sent + the preview flag is NOT set. $this->deleteRecord(); } // If incoming data is seen... if (is_array($this->dataArr)) { // Evaluation of data: $this->parseValues(); $this->overrideValues(); $this->evalValues(); if ($this->conf['evalFunc']) { $this->dataArr = $this->userProcess('evalFunc',$this->dataArr); } /* debug($this->dataArr); debug($this->failure); debug($this->preview); */ // if not preview and no failures, then set data... if (!$this->failure && !$this->preview && !t3lib_div::_GP('doNotSave')) { // doNotSave is a global var (eg a 'Cancel' submit button) that prevents the data from being processed $this->save(); } else { if ($this->conf['debug']) debug($this->failure); } } else { $this->defaultValues(); // If no incoming data, this will set the default values. $this->preview = 0; // No preview if data is not received } if ($this->failure) {$this->preview=0;} // No preview flag if a evaluation failure has occured $this->previewLabel = $this->preview ? '_PREVIEW' : ''; // Setting preview label prefix. // ********************* // DISPLAY FORMS: // *********************** if ($this->saved) { // Clear page cache $this->clearCacheIfSet(); // Displaying the page here that says, the record has been saved. You're able to include the saved values by markers. switch($this->cmd) { case 'delete': $key='DELETE'; break; case 'edit': $key='EDIT'; break; default: $key='CREATE'; break; } // Output message $templateCode = $this->cObj->getSubpart($this->templateCode, '###TEMPLATE_'.$key.'_SAVED###'); $this->setCObjects($templateCode,$this->currentArr); $markerArray = $this->cObj->fillInMarkerArray($this->markerArray, $this->currentArr, '', TRUE, 'FIELD_', $this->recInMarkersHSC); $content = $this->cObj->substituteMarkerArray($templateCode, $markerArray); // email message: $this->compileMail( $key.'_SAVED', array($this->currentArr), $this->currentArr[$this->conf['email.']['field']], $this->conf['setfixed.'] ); } elseif ($this->error) { // If there was an error, we return the template-subpart with the error message $templateCode = $this->cObj->getSubpart($this->templateCode, $this->error); $this->setCObjects($templateCode); $content = $this->cObj->substituteMarkerArray($templateCode, $this->markerArray); } else { // Finally, if there has been no attempt to save. That is either preview or just displaying and empty or not correctly filled form: if (!$this->cmd) { $this->cmd=$this->conf['defaultCmd']; } if ($this->conf['debug']) debug('Display form: '.$this->cmd,1); switch($this->cmd) { case 'setfixed': $content = $this->procesSetFixed(); break; case 'infomail': $content = $this->sendInfoMail(); break; case 'delete': $content = $this->displayDeleteScreen(); break; case 'edit': $content = $this->displayEditScreen(); break; case 'create': $content = $this->displayCreateScreen(); break; } } // Delete temp files: foreach($this->unlinkTempFiles as $tempFileName) { t3lib_div::unlink_tempfile($tempFileName); } // Return content: return $content; } /***************************************** * * Data processing * *****************************************/ /** * Performs processing on the values found in the input data array, $this->dataArr. * The processing is done according to configuration found in TypoScript * Examples of this could be to force a value to an integer, remove all non-alphanumeric characters, trimming a value, upper/lowercase it, or process it due to special types like files submitted etc. * Called from init() if the $this->dataArr is found to be an array * * @return void * @see init() */ function parseValues() { if (is_array($this->conf['parseValues.'])) { reset($this->conf['parseValues.']); while(list($theField,$theValue)=each($this->conf['parseValues.'])) { $listOfCommands = t3lib_div::trimExplode(',',$theValue,1); while(list(,$cmd)=each($listOfCommands)) { $cmdParts = split('\[|\]',$cmd); // Point is to enable parameters after each command enclosed in brackets [..]. These will be in position 1 in the array. $theCmd=trim($cmdParts[0]); switch($theCmd) { case 'int': $this->dataArr[$theField]=intval($this->dataArr[$theField]); break; case 'lower': case 'upper': $this->dataArr[$theField] = $this->cObj->caseshift($this->dataArr[$theField],$theCmd); break; case 'nospace': $this->dataArr[$theField] = str_replace(' ', '', $this->dataArr[$theField]); break; case 'alpha': $this->dataArr[$theField] = ereg_replace('[^a-zA-Z]','',$this->dataArr[$theField]); break; case 'num': $this->dataArr[$theField] = ereg_replace('[^0-9]','',$this->dataArr[$theField]); break; case 'alphanum': $this->dataArr[$theField] = ereg_replace('[^a-zA-Z0-9]','',$this->dataArr[$theField]); break; case 'alphanum_x': $this->dataArr[$theField] = ereg_replace('[^a-zA-Z0-9_-]','',$this->dataArr[$theField]); break; case 'trim': $this->dataArr[$theField] = trim($this->dataArr[$theField]); break; case 'random': $this->dataArr[$theField] = substr(md5(uniqid(microtime(),1)),0,intval($cmdParts[1])); break; case 'files': if ($this->cmdKey=='create' && !t3lib_div::_GP('doNotSave')) { $this->processFiles($cmdParts,$theField); } else unset($this->dataArr[$theField]); // Fields with files cannot be edited - only created. break; case 'setEmptyIfAbsent': if (!isset($this->dataArr[$theField])) { $this->dataArr[$theField]=''; } break; case 'multiple': if (is_array($this->dataArr[$theField])) { $this->dataArr[$theField] = implode(',',$this->dataArr[$theField]); } break; case 'checkArray': if (is_array($this->dataArr[$theField])) { reset($this->dataArr[$theField]); $val = 0; while(list($kk,$vv)=each($this->dataArr[$theField])) { $kk = t3lib_div::intInRange($kk,0); if ($kk<=30) { if ($vv) { $val|=pow(2,$kk); } } } $this->dataArr[$theField] = $val; } else {$this->dataArr[$theField]=0;} break; case 'uniqueHashInt': $otherFields = t3lib_div::trimExplode(';',$cmdParts[1],1); $hashArray=array(); while(list(,$fN)=each($otherFields)) { $vv = $this->dataArr[$fN]; $vv = ereg_replace('[[:space:]]','',$vv); $vv = ereg_replace('[^[:alnum:]]','',$vv); $vv = strtolower($vv); $hashArray[]=$vv; } $this->dataArr[$theField]=hexdec(substr(md5(serialize($hashArray)),0,8)); break; } } } } } /** * Processing of files. * NOTICE: for now files can be handled only on creation of records. But a more advanced feature is that PREVIEW of files is handled. * * @param array Array with cmd-parts (from parseValues()). This will for example contain information about allowed file extensions and max size of uploaded files. * @param string The fieldname with the files. * @return void * @access private * @see parseValues() */ function processFiles($cmdParts,$theField) { //debug($_FILES); // First, make an array with the filename and file reference, whether the file is just uploaded or a preview $filesArr = array(); if (is_string($this->dataArr[$theField])) { // files from preview. $tmpArr = explode(',',$this->dataArr[$theField]); reset($tmpArr); while(list(,$val)=each($tmpArr)) { $valParts = explode('|',$val); $filesArr[] = array ( 'name'=>$valParts[1], 'tmp_name'=>PATH_site.'typo3temp/'.$valParts[0] ); } } elseif (is_array($_FILES['FE'][$this->theTable][$theField]['name'])) { // Files from upload reset($_FILES['FE'][$this->theTable][$theField]['name']); while(list($kk,$vv)=each($_FILES['FE'][$this->theTable][$theField]['name'])) { if ($vv) { $tmpFile = t3lib_div::upload_to_tempfile($_FILES['FE'][$this->theTable][$theField]['tmp_name'][$kk]); if ($tmpFile) { $this->unlinkTempFiles[]=$tmpFile; $filesArr[] = array ( 'name'=>$vv, 'tmp_name'=>$tmpFile ); } } } } elseif (is_array($_FILES['FE']['name'][$this->theTable][$theField])) { // Files from upload reset($_FILES['FE']['name'][$this->theTable][$theField]); while(list($kk,$vv)=each($_FILES['FE']['name'][$this->theTable][$theField])) { if ($vv) { $tmpFile = t3lib_div::upload_to_tempfile($_FILES['FE']['tmp_name'][$this->theTable][$theField][$kk]); if ($tmpFile) { $this->unlinkTempFiles[]=$tmpFile; $filesArr[] = array ( 'name'=>$vv, 'tmp_name'=>$tmpFile ); } } } } // Then verify the files in that array; check existence, extension and size $this->dataArr[$theField]=''; $finalFilesArr=array(); if (count($filesArr)) { $extArray = t3lib_div::trimExplode(';',strtolower($cmdParts[1]),1); $maxSize = intval($cmdParts[3]); reset($filesArr); while(list(,$infoArr)=each($filesArr)) { $fI = pathinfo($infoArr['name']); if (t3lib_div::verifyFilenameAgainstDenyPattern($fI['name'])) { if (!count($extArray) || in_array(strtolower($fI['extension']), $extArray)) { $tmpFile = $infoArr['tmp_name']; if (@is_file($tmpFile)) { if (!$maxSize || filesize($tmpFile)<$maxSize*1024) { $finalFilesArr[]=$infoArr; } elseif ($this->conf['debug']) {debug('Size is beyond '.$maxSize.' kb ('.filesize($tmpFile).' bytes) and the file cannot be saved.');} } elseif ($this->conf['debug']) {debug('Surprisingly there was no file for '.$vv.' in '.$tmpFile);} } elseif ($this->conf['debug']) {debug('Extension "'.$fI['extension'].'" not allowed');} } elseif ($this->conf['debug']) {debug('Filename matched illegal pattern.');} } } // Copy the files in the resulting array to the proper positions based on preview/non-preview. reset($finalFilesArr); $fileNameList=array(); while(list(,$infoArr)=each($finalFilesArr)) { if ($this->isPreview()) { // If the form is a preview form (and data is therefore not going into the database...) do this. $this->createFileFuncObj(); $fI = pathinfo($infoArr['name']); $tmpFilename = $this->theTable.'_'.t3lib_div::shortmd5(uniqid($infoArr['name'])).'.'.$fI['extension']; $theDestFile = $this->fileFunc->getUniqueName($this->fileFunc->cleanFileName($tmpFilename), PATH_site.'typo3temp/'); t3lib_div::upload_copy_move($infoArr['tmp_name'],$theDestFile); // Setting the filename in the list $fI2 = pathinfo($theDestFile); $fileNameList[] = $fI2['basename'].'|'.$infoArr['name']; } else { $this->createFileFuncObj(); $GLOBALS['TSFE']->includeTCA(); t3lib_div::loadTCA($this->theTable); if (is_array($GLOBALS['TCA'][$this->theTable]['columns'][$theField])) { $uploadPath = $GLOBALS['TCA'][$this->theTable]['columns'][$theField]['config']['uploadfolder']; } if ($uploadPath) { $theDestFile = $this->fileFunc->getUniqueName($this->fileFunc->cleanFileName($infoArr['name']), PATH_site.$uploadPath); t3lib_div::upload_copy_move($infoArr['tmp_name'],$theDestFile); // Setting the filename in the list $fI2 = pathinfo($theDestFile); $fileNameList[] = $fI2['basename']; $this->filesStoredInUploadFolders[]=$theDestFile; } } // Implode the list of filenames $this->dataArr[$theField] = implode(',',$fileNameList); } } /** * Overriding values in $this->dataArr if configured for that in TypoScript ([edit/create].overrideValues) * * @return void * @see init() */ function overrideValues() { // Addition of overriding values if (is_array($this->conf[$this->cmdKey.'.']['overrideValues.'])) { reset($this->conf[$this->cmdKey.'.']['overrideValues.']); while(list($theField,$theValue)=each($this->conf[$this->cmdKey.'.']['overrideValues.'])) { $this->dataArr[$theField] = $theValue; } } } /** * Called if there is no input array in $this->dataArr. Then this function sets the default values configured in TypoScript * * @return void * @see init() */ function defaultValues() { // Addition of default values if (is_array($this->conf[$this->cmdKey.'.']['defaultValues.'])) { reset($this->conf[$this->cmdKey.'.']['defaultValues.']); while(list($theField,$theValue)=each($this->conf[$this->cmdKey.'.']['defaultValues.'])) { $this->dataArr[$theField] = $theValue; } } } /** * This will evaluate the input values from $this->dataArr to see if they conforms with the requirements configured in TypoScript per field. * For example this could be checking if a field contains a valid email address, a unique value, a value within a certain range etc. * It will populate arrays like $this->failure and $this->failureMsg with error messages (which can later be displayed in the template). Mostly it does NOT alter $this->dataArr (such parsing of values was done by parseValues()) * Works based on configuration in TypoScript key [create/edit].evalValues * * @return void * @see init(), parseValues() */ function evalValues() { // Check required, set failure if not ok. reset($this->requiredArr); $tempArr=array(); while(list(,$theField)=each($this->requiredArr)) { if (!trim($this->dataArr[$theField])) { $tempArr[]=$theField; } } // Evaluate: This evaluates for more advanced things than 'required' does. But it returns the same error code, so you must let the required-message tell, if further evaluation has failed! $recExist=0; if (is_array($this->conf[$this->cmdKey.'.']['evalValues.'])) { switch($this->cmd) { case 'edit': if (isset($this->dataArr['pid'])) { // This may be tricked if the input has the pid-field set but the edit-field list does NOT allow the pid to be edited. Then the pid may be false. $recordTestPid = intval($this->dataArr['pid']); } else { $tempRecArr = $GLOBALS['TSFE']->sys_page->getRawRecord($this->theTable,$this->dataArr['uid']); $recordTestPid = intval($tempRecArr['pid']); } $recExist=1; break; default: $recordTestPid = $this->thePid ? $this->thePid : t3lib_div::intval_positive($this->dataArr['pid']); break; } reset($this->conf[$this->cmdKey.'.']['evalValues.']); while(list($theField,$theValue)=each($this->conf[$this->cmdKey.'.']['evalValues.'])) { $listOfCommands = t3lib_div::trimExplode(',',$theValue,1); while(list(,$cmd)=each($listOfCommands)) { $cmdParts = split('\[|\]',$cmd); // Point is to enable parameters after each command enclosed in brackets [..]. These will be in position 1 in the array. $theCmd = trim($cmdParts[0]); switch($theCmd) { case 'uniqueGlobal': if ($DBrows = $GLOBALS['TSFE']->sys_page->getRecordsByField($this->theTable,$theField,$this->dataArr[$theField],'','','','1')) { if (!$recExist || $DBrows[0]['uid']!=$this->dataArr['uid']) { // Only issue an error if the record is not existing (if new...) and if the record with the false value selected was not our self. $tempArr[]=$theField; $this->failureMsg[$theField][] = $this->getFailure($theField, $theCmd, 'The value existed already. Enter a new value.'); } } break; case 'uniqueLocal': if ($DBrows = $GLOBALS['TSFE']->sys_page->getRecordsByField($this->theTable,$theField,$this->dataArr[$theField], 'AND pid IN ('.$recordTestPid.')','','','1')) { if (!$recExist || $DBrows[0]['uid']!=$this->dataArr['uid']) { // Only issue an error if the record is not existing (if new...) and if the record with the false value selected was not our self. $tempArr[]=$theField; $this->failureMsg[$theField][] = $this->getFailure($theField, $theCmd, 'The value existed already. Enter a new value.'); } } break; case 'twice': if (strcmp($this->dataArr[$theField], $this->dataArr[$theField.'_again'])) { $tempArr[]=$theField; $this->failureMsg[$theField][] = $this->getFailure($theField, $theCmd, 'You must enter the same value twice'); } break; case 'email': if (!$this->cObj->checkEmail($this->dataArr[$theField])) { $tempArr[]=$theField; $this->failureMsg[$theField][] = $this->getFailure($theField, $theCmd, 'You must enter a valid email address'); } break; case 'required': if (!trim($this->dataArr[$theField])) { $tempArr[]=$theField; $this->failureMsg[$theField][] = $this->getFailure($theField, $theCmd, 'You must enter a value!'); } break; case 'atLeast': $chars=intval($cmdParts[1]); if (strlen($this->dataArr[$theField])<$chars) { $tempArr[]=$theField; $this->failureMsg[$theField][] = sprintf($this->getFailure($theField, $theCmd, 'You must enter at least %s characters!'), $chars); } break; case 'atMost': $chars=intval($cmdParts[1]); if (strlen($this->dataArr[$theField])>$chars) { $tempArr[]=$theField; $this->failureMsg[$theField][] = sprintf($this->getFailure($theField, $theCmd, 'You must enter at most %s characters!'), $chars); } break; case 'inBranch': $pars = explode(';',$cmdParts[1]); if (intval($pars[0])) { $pid_list = $this->cObj->getTreeList( intval($pars[0]), intval($pars[1]) ? intval($pars[1]) : 999, intval($pars[2]) ); if (!$pid_list || !t3lib_div::inList($pid_list,$this->dataArr[$theField])) { $tempArr[]=$theField; $this->failureMsg[$theField][] = sprintf($this->getFailure($theField, $theCmd, 'The value was not a valid valud from this list: %s'), $pid_list); } } break; case 'unsetEmpty': if (!$this->dataArr[$theField]) { $hash = array_flip($tempArr); unset($hash[$theField]); $tempArr = array_keys($hash); unset($this->failureMsg[$theField]); unset($this->dataArr[$theField]); // This should prevent the field from entering the database. } break; } } $this->markerArray['###EVAL_ERROR_FIELD_'.$theField.'###'] = is_array($this->failureMsg[$theField]) ? implode('
',$this->failureMsg[$theField]) : ''; } } $this->failure=implode(',',$tempArr); //$failure will show which fields were not OK } /** * Preforms user processing of input array - triggered right after the function call to evalValues() IF TypoScript property "evalFunc" was set. * * @param string Key pointing to the property in TypoScript holding the configuration for this processing (here: "evalFunc.*"). Well: at least its safe to say that "parentObj" in this array passed to the function is a reference back to this object. * @param array The $this->dataArr passed for processing * @return array The processed $passVar ($this->dataArr) * @see init(), evalValues() */ function userProcess($mConfKey,$passVar) { if ($this->conf[$mConfKey]) { $funcConf = $this->conf[$mConfKey.'.']; $funcConf['parentObj']=&$this; $passVar = $GLOBALS['TSFE']->cObj->callUserFunction($this->conf[$mConfKey], $funcConf, $passVar); } return $passVar; } /** * User processing of contnet * * @param string Value of the TypoScript object triggering the processing. * @param array Properties of the TypoScript object triggering the processing. The key "parentObj" in this array is passed to the function as a reference back to this object. * @param mixed Input variable to process * @return mixed Processed input variable, $passVar * @see userProcess(), save(), modifyDataArrForFormUpdate() */ function userProcess_alt($confVal,$confArr,$passVar) { if ($confVal) { $funcConf = $confArr; $funcConf['parentObj']=&$this; $passVar = $GLOBALS['TSFE']->cObj->callUserFunction($confVal, $funcConf, $passVar); } return $passVar; } /***************************************** * * Database manipulation functions * *****************************************/ /** * Performs the saving of records, either edited or created. * * @return void * @see init() */ function save() { switch($this->cmd) { case 'edit': $theUid = $this->dataArr['uid']; $origArr = $GLOBALS['TSFE']->sys_page->getRawRecord($this->theTable,$theUid); // Fetches the original record to check permissions if ($this->conf['edit'] && ($GLOBALS['TSFE']->loginUser || $this->aCAuth($origArr))) { // Must be logged in in order to edit (OR be validated by email) $newFieldList = implode(',',array_intersect(explode(',',$this->fieldList),t3lib_div::trimExplode(',',$this->conf['edit.']['fields'],1))); if ($this->aCAuth($origArr) || $this->cObj->DBmayFEUserEdit($this->theTable,$origArr,$GLOBALS['TSFE']->fe_user->user,$this->conf['allowedGroups'],$this->conf['fe_userEditSelf'])) { $this->cObj->DBgetUpdate($this->theTable, $theUid, $this->dataArr, $newFieldList, TRUE); $this->currentArr = $GLOBALS['TSFE']->sys_page->getRawRecord($this->theTable,$theUid); $this->userProcess_alt($this->conf['edit.']['userFunc_afterSave'],$this->conf['edit.']['userFunc_afterSave.'],array('rec'=>$this->currentArr, 'origRec'=>$origArr)); $this->saved=1; } else { $this->error='###TEMPLATE_NO_PERMISSIONS###'; } } break; default: if ($this->conf['create']) { $newFieldList = implode(',',array_intersect(explode(',',$this->fieldList),t3lib_div::trimExplode(',',$this->conf['create.']['fields'],1))); $this->cObj->DBgetInsert($this->theTable, $this->thePid, $this->dataArr, $newFieldList, TRUE); $newId = $GLOBALS['TYPO3_DB']->sql_insert_id(); if ($this->theTable=='fe_users' && $this->conf['fe_userOwnSelf']) { // enables users, creating logins, to own them self. $extraList=''; $dataArr = array(); if ($GLOBALS['TCA'][$this->theTable]['ctrl']['fe_cruser_id']) { $field=$GLOBALS['TCA'][$this->theTable]['ctrl']['fe_cruser_id']; $dataArr[$field]=$newId; $extraList.=','.$field; } if ($GLOBALS['TCA'][$this->theTable]['ctrl']['fe_crgroup_id']) { $field=$GLOBALS['TCA'][$this->theTable]['ctrl']['fe_crgroup_id']; list($dataArr[$field])=explode(',',$this->dataArr['usergroup']); $dataArr[$field]=intval($dataArr[$field]); $extraList.=','.$field; } if (count($dataArr)) { $this->cObj->DBgetUpdate($this->theTable, $newId, $dataArr, $extraList, TRUE); } } $this->currentArr = $GLOBALS['TSFE']->sys_page->getRawRecord($this->theTable,$newId); $this->userProcess_alt($this->conf['create.']['userFunc_afterSave'],$this->conf['create.']['userFunc_afterSave.'],array('rec'=>$this->currentArr)); $this->saved=1; } break; } } /** * Deletes the record from table/uid, $this->theTable/$this->recUid, IF the fe-user has permission to do so. * If the deleted flag should just be set, then it is done so. Otherwise the record truely is deleted along with any attached files. * Called from init() if "cmd" was set to "delete" (and some other conditions) * * @return string void * @see init() */ function deleteRecord() { if ($this->conf['delete']) { // If deleting is enabled $origArr = $GLOBALS['TSFE']->sys_page->getRawRecord($this->theTable, $this->recUid); if ($GLOBALS['TSFE']->loginUser || $this->aCAuth($origArr)) { // Must be logged in OR be authenticated by the aC code in order to delete // If the recUid selects a record.... (no check here) if (is_array($origArr)) { if ($this->aCAuth($origArr) || $this->cObj->DBmayFEUserEdit($this->theTable,$origArr, $GLOBALS['TSFE']->fe_user->user,$this->conf['allowedGroups'],$this->conf['fe_userEditSelf'])) { // Display the form, if access granted. if (!$GLOBALS['TCA'][$this->theTable]['ctrl']['delete']) { // If the record is fully deleted... then remove the image (or any file) attached. $this->deleteFilesFromRecord($this->recUid); } $this->cObj->DBgetDelete($this->theTable, $this->recUid, TRUE); $this->currentArr = $origArr; $this->saved = 1; } else { $this->error = '###TEMPLATE_NO_PERMISSIONS###'; } } } } } /** * Deletes the files attached to a record and updates the record. * Table/uid is $this->theTable/$uid * * @param integer Uid number of the record to delete from $this->theTable * @return void * @access private * @see deleteRecord() */ function deleteFilesFromRecord($uid) { $table = $this->theTable; $rec = $GLOBALS['TSFE']->sys_page->getRawRecord($table,$uid); $GLOBALS['TSFE']->includeTCA(); t3lib_div::loadTCA($table); reset($GLOBALS['TCA'][$table]['columns']); $iFields=array(); while(list($field,$conf)=each($GLOBALS['TCA'][$table]['columns'])) { if ($conf['config']['type']=='group' && $conf['config']['internal_type']=='file') { $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid='.intval($uid), array($field => '')); $delFileArr = explode(',',$rec[$field]); reset($delFileArr); while(list(,$n)=each($delFileArr)) { if ($n) { $fpath = $conf['config']['uploadfolder'].'/'.$n; unlink($fpath); } } } } } /***************************************** * * Command "display" functions * *****************************************/ /** * Creates the preview display of delete actions * * @return string HTML content * @see init() */ function displayDeleteScreen() { if ($this->conf['delete']) { // If deleting is enabled $origArr = $GLOBALS['TSFE']->sys_page->getRawRecord($this->theTable, $this->recUid); if ($GLOBALS['TSFE']->loginUser || $this->aCAuth($origArr)) { // Must be logged in OR be authenticated by the aC code in order to delete // If the recUid selects a record.... (no check here) if (is_array($origArr)) { if ($this->aCAuth($origArr) || $this->cObj->DBmayFEUserEdit($this->theTable,$origArr, $GLOBALS['TSFE']->fe_user->user,$this->conf['allowedGroups'],$this->conf['fe_userEditSelf'])) { // Display the form, if access granted. $this->markerArray['###HIDDENFIELDS###'].= ''; $content = $this->getPlainTemplate('###TEMPLATE_DELETE_PREVIEW###', $origArr); } else { // Else display error, that you could not edit that particular record... $content = $this->getPlainTemplate('###TEMPLATE_NO_PERMISSIONS###'); } } } else { // Finally this is if there is no login user. This must tell that you must login. Perhaps link to a page with create-user or login information. $content = $this->getPlainTemplate('###TEMPLATE_AUTH###'); } } else { $content.='Delete-option is not set in TypoScript'; } return $content; } /** * Creates the "create" screen for records * * @return string HTML content * @see init() */ function displayCreateScreen() { if ($this->conf['create']) { $templateCode = $this->cObj->getSubpart($this->templateCode, ((!$GLOBALS['TSFE']->loginUser||$this->conf['create.']['noSpecialLoginForm'])?'###TEMPLATE_CREATE'.$this->previewLabel.'###':'###TEMPLATE_CREATE_LOGIN'.$this->previewLabel.'###')); $failure = t3lib_div::_GP('noWarnings')?'':$this->failure; if (!$failure) $templateCode = $this->cObj->substituteSubpart($templateCode, '###SUB_REQUIRED_FIELDS_WARNING###', ''); $templateCode = $this->removeRequired($templateCode,$failure); $this->setCObjects($templateCode); $markerArray = $this->cObj->fillInMarkerArray($this->markerArray, $this->dataArr, '', TRUE, 'FIELD_', $this->recInMarkersHSC); if ($this->conf['create.']['preview'] && !$this->previewLabel) {$markerArray['###HIDDENFIELDS###'].= '';} $content = $this->cObj->substituteMarkerArray($templateCode, $markerArray); $content.=$this->cObj->getUpdateJS($this->modifyDataArrForFormUpdate($this->dataArr), $this->theTable.'_form', 'FE['.$this->theTable.']', $this->fieldList.$this->additionalUpdateFields); } return $content; } /** * Creates the edit-screen for records * * @return string HTML content * @see init() */ function displayEditScreen() { if ($this->conf['edit']) { // If editing is enabled $origArr = $GLOBALS['TSFE']->sys_page->getRawRecord($this->theTable, $this->dataArr['uid']?$this->dataArr['uid']:$this->recUid); if ($GLOBALS['TSFE']->loginUser || $this->aCAuth($origArr)) { // Must be logged in OR be authenticated by the aC code in order to edit // If the recUid selects a record.... (no check here) if (is_array($origArr)) { if ($this->aCAuth($origArr) || $this->cObj->DBmayFEUserEdit($this->theTable,$origArr, $GLOBALS['TSFE']->fe_user->user,$this->conf['allowedGroups'],$this->conf['fe_userEditSelf'])) { // Display the form, if access granted. $content=$this->displayEditForm($origArr); } else { // Else display error, that you could not edit that particular record... $content = $this->getPlainTemplate('###TEMPLATE_NO_PERMISSIONS###'); } } elseif ($GLOBALS['TSFE']->loginUser) { // If the recUid did not select a record, we display a menu of records. (eg. if no recUid) $lockPid = $this->conf['edit.']['menuLockPid'] ? ' AND pid='.intval($this->thePid) : ''; $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $this->theTable, '1 '.$lockPid.$this->cObj->DBmayFEUserEditSelect($this->theTable,$GLOBALS['TSFE']->fe_user->user, $this->conf['allowedGroups'],$this->conf['fe_userEditSelf']).$GLOBALS['TSFE']->sys_page->deleteClause($this->theTable)); if ($GLOBALS['TYPO3_DB']->sql_num_rows($res)) { // If there are menu-items ... $templateCode = $this->getPlainTemplate('###TEMPLATE_EDITMENU###'); $out=''; $itemCode = $this->cObj->getSubpart($templateCode, '###ITEM###'); while($menuRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { $markerArray = $this->cObj->fillInMarkerArray(array(), $menuRow, '', TRUE, 'FIELD_', $this->recInMarkersHSC); $markerArray = $this->setCObjects($itemCode,$menuRow,$markerArray,'ITEM_'); $out.= $this->cObj->substituteMarkerArray($itemCode, $markerArray); } $content=$this->cObj->substituteSubpart($templateCode, '###ALLITEMS###', $out); } else { // If there are not menu items.... $content = $this->getPlainTemplate('###TEMPLATE_EDITMENU_NOITEMS###'); } } else { $content = $this->getPlainTemplate('###TEMPLATE_AUTH###'); } } else { // Finally this is if there is no login user. This must tell that you must login. Perhaps link to a page with create-user or login information. $content = $this->getPlainTemplate('###TEMPLATE_AUTH###'); } } else { $content.='Edit-option is not set in TypoScript'; } return $content; } /** * Subfunction for displayEditScreen(); Takes a record and creates an edit form based on the template code for it. * This function is called if the user is editing a record and permitted to do so. Checked in displayEditScreen() * * @param array The array with the record to edit * @return string HTML content * @access private * @see displayEditScreen() */ function displayEditForm($origArr) { $currentArr = is_array($this->dataArr) ? $this->dataArr+$origArr : $origArr; if ($this->conf['debug']) debug('displayEditForm(): '.'###TEMPLATE_EDIT'.$this->previewLabel.'###',1); $templateCode = $this->cObj->getSubpart($this->templateCode, '###TEMPLATE_EDIT'.$this->previewLabel.'###'); $failure = t3lib_div::_GP('noWarnings')?'':$this->failure; if (!$failure) {$templateCode = $this->cObj->substituteSubpart($templateCode, '###SUB_REQUIRED_FIELDS_WARNING###', '');} $templateCode = $this->removeRequired($templateCode,$failure); $this->setCObjects($templateCode,$currentArr); $markerArray = $this->cObj->fillInMarkerArray($this->markerArray, $currentArr, '', TRUE, 'FIELD_', $this->recInMarkersHSC); $markerArray['###HIDDENFIELDS###'].= ''; if ($this->conf['edit.']['preview'] && !$this->previewLabel) {$markerArray['###HIDDENFIELDS###'].= '';} $content = $this->cObj->substituteMarkerArray($templateCode, $markerArray); $content.=$this->cObj->getUpdateJS($this->modifyDataArrForFormUpdate($currentArr), $this->theTable.'_form', 'FE['.$this->theTable.']', $this->fieldList.$this->additionalUpdateFields); return $content; } /** * Processes socalled "setfixed" commands. These are commands setting a certain field in a certain record to a certain value. Like a link you can click in an email which will unhide a record to enable something. Or likewise a link which can delete a record by a single click. * The idea is that only some allowed actions like this is allowed depending on the configured TypoScript. * * @return string HTML content displaying the status of the action */ function procesSetFixed() { if ($this->conf['setfixed']) { $theUid = intval($this->recUid); $origArr = $GLOBALS['TSFE']->sys_page->getRawRecord($this->theTable, $theUid); $fD = t3lib_div::_GP('fD'); $sFK = t3lib_div::_GP('sFK'); $fieldArr=array(); if (is_array($fD) || $sFK=='DELETE') { if (is_array($fD)) { reset($fD); while(list($field,$value)=each($fD)) { $origArr[$field]=$value; $fieldArr[]=$field; } } $theCode = $this->setfixedHash($origArr,$origArr['_FIELDLIST']); if (!strcmp($this->authCode,$theCode)) { if ($sFK=='DELETE') { $this->cObj->DBgetDelete($this->theTable, $theUid, TRUE); } else { $newFieldList = implode(',',array_intersect(t3lib_div::trimExplode(',',$this->fieldList),t3lib_div::trimExplode(',',implode($fieldArr,','),1))); $this->cObj->DBgetUpdate($this->theTable, $theUid, $fD, $newFieldList, TRUE); $this->currentArr = $GLOBALS['TSFE']->sys_page->getRawRecord($this->theTable,$theUid); $this->userProcess_alt($this->conf['setfixed.']['userFunc_afterSave'],$this->conf['setfixed.']['userFunc_afterSave.'],array('rec'=>$this->currentArr, 'origRec'=>$origArr)); } // Outputting template $this->markerArray = $this->cObj->fillInMarkerArray($this->markerArray, $origArr, '', TRUE, 'FIELD_', $this->recInMarkersHSC); $content = $this->getPlainTemplate('###TEMPLATE_SETFIXED_OK_'.$sFK.'###'); if (!$content) {$content = $this->getPlainTemplate('###TEMPLATE_SETFIXED_OK###');} // Compiling email $this->compileMail( 'SETFIXED_'.$sFK, array($origArr), $origArr[$this->conf['email.']['field']], $this->conf['setfixed.'] ); // Clearing cache if set: $this->clearCacheIfSet(); } else $content = $this->getPlainTemplate('###TEMPLATE_SETFIXED_FAILED###'); } else $content = $this->getPlainTemplate('###TEMPLATE_SETFIXED_FAILED###'); } return $content; } /***************************************** * * Template processing functions * *****************************************/ /** * Remove required parts from template code string * Works like this: * - You insert subparts like this ###SUB_REQUIRED_FIELD_'.$theField.'### in the template that tells what is required for the field, if it's not correct filled in. * - These subparts are all removed, except if the field is listed in $failure string! * * Only fields that are found in $this->requiredArr is processed. * * @param string The template HTML code * @param string Comma list of fields which has errors (and therefore should not be removed) * @return string The processed template HTML code */ function removeRequired($templateCode,$failure) { reset($this->requiredArr); while(list(,$theField)=each($this->requiredArr)) { if (!t3lib_div::inList($failure,$theField)) { $templateCode = $this->cObj->substituteSubpart($templateCode, '###SUB_REQUIRED_FIELD_'.$theField.'###', ''); } } return $templateCode; } /** * Returns template subpart HTML code for the key given * * @param string Subpart marker to return subpart for. * @param array Optional data record array. If set, then all fields herein will also be substituted if found as markers in the template * @return string The subpart with all markers found in current $this->markerArray substituted. * @see tslib_cObj::fillInMarkerArray() */ function getPlainTemplate($key,$r='') { if ($this->conf['debug']) debug('getPlainTemplate(): '.$key,1); $templateCode = $this->cObj->getSubpart($this->templateCode, $key); $this->setCObjects($templateCode,is_array($r)?$r:array()); return $this->cObj->substituteMarkerArray( $templateCode, is_array($r) ? $this->cObj->fillInMarkerArray($this->markerArray, $r, '', TRUE, 'FIELD_', $this->recInMarkersHSC) : $this->markerArray ); } /** * Modifies input array for passing on to tslib_cObj::getUpdateJS() which produces some JavaScript for form evaluation or the like. * * @param array The data array * @return array The processed input array * @see displayCreateScreen(), displayEditForm(), tslib_cObj::getUpdateJS() */ function modifyDataArrForFormUpdate($inputArr) { if (is_array($this->conf[$this->cmdKey.'.']['evalValues.'])) { reset($this->conf[$this->cmdKey.'.']['evalValues.']); while(list($theField,$theValue)=each($this->conf[$this->cmdKey.'.']['evalValues.'])) { $listOfCommands = t3lib_div::trimExplode(',',$theValue,1); while(list(,$cmd)=each($listOfCommands)) { $cmdParts = split('\[|\]',$cmd); // Point is to enable parameters after each command enclosed in brackets [..]. These will be in position 1 in the array. $theCmd = trim($cmdParts[0]); switch($theCmd) { case 'twice': if (isset($inputArr[$theField])) { if (!isset($inputArr[$theField.'_again'])) { $inputArr[$theField.'_again'] = $inputArr[$theField]; } $this->additionalUpdateFields.=','.$theField.'_again'; } break; } } } } if (is_array($this->conf['parseValues.'])) { reset($this->conf['parseValues.']); while(list($theField,$theValue)=each($this->conf['parseValues.'])) { $listOfCommands = t3lib_div::trimExplode(',',$theValue,1); while(list(,$cmd)=each($listOfCommands)) { $cmdParts = split('\[|\]',$cmd); // Point is to enable parameters after each command enclosed in brackets [..]. These will be in position 1 in the array. $theCmd = trim($cmdParts[0]); switch($theCmd) { case 'multiple': if (isset($inputArr[$theField]) && !$this->isPreview()) { $inputArr[$theField] = explode(',',$inputArr[$theField]); } break; case 'checkArray': if ($inputArr[$theField] && !$this->isPreview()) { for($a=0;$a<=30;$a++) { if ($inputArr[$theField] & pow(2,$a)) { $alt_theField = $theField.']['.$a; $inputArr[$alt_theField] = 1; $this->additionalUpdateFields.=','.$alt_theField; } } } break; } } } } $inputArr = $this->userProcess_alt( $this->conf['userFunc_updateArray'], $this->conf['userFunc_updateArray.'], $inputArr ); return $inputArr; } /** * Will render TypoScript cObjects (configured in $this->conf['cObjects.']) and add their content to keys in a markerArray, either the array passed to the function or the internal one ($this->markerArray) if the input $markerArray is not set. * * @param string The current template code string. Is used to check if the marker string is found and if not, the content object is not rendered! * @param array An alternative data record array (if empty then $this->dataArr is used) * @param mixed An alternative markerArray to fill in (instead of $this->markerArray). If you want to set the cobjects in the internal $this->markerArray, then just set this to non-array value. * @param string Optional prefix to set for the marker strings. * @return array The processed $markerArray (if given). */ function setCObjects($templateCode,$currentArr=array(),$markerArray='',$specialPrefix='') { if (is_array($this->conf['cObjects.'])) { reset($this->conf['cObjects.']); while(list($theKey,$theConf)=each($this->conf['cObjects.'])) { if (!strstr($theKey,'.')) { if (strstr($templateCode,'###'.$specialPrefix.'CE_'.$theKey.'###')) { $cObjCode = $this->cObj->cObjGetSingle($this->conf['cObjects.'][$theKey], $this->conf['cObjects.'][$theKey.'.'], 'cObjects.'.$theKey); if (!is_array($markerArray)) { $this->markerArray['###'.$specialPrefix.'CE_'.$theKey.'###'] = $cObjCode; } else { $markerArray['###'.$specialPrefix.'CE_'.$theKey.'###'] = $cObjCode; } } if (strstr($templateCode,'###'.$specialPrefix.'PCE_'.$theKey.'###')) { $local_cObj =t3lib_div::makeInstance('tslib_cObj'); $local_cObj->start(count($currentArr)?$currentArr:$this->dataArr,$this->theTable); $cObjCode = $local_cObj->cObjGetSingle($this->conf['cObjects.'][$theKey], $this->conf['cObjects.'][$theKey.'.'], 'cObjects.'.$theKey); if (!is_array($markerArray)) { $this->markerArray['###'.$specialPrefix.'PCE_'.$theKey.'###'] = $cObjCode; } else { $markerArray['###'.$specialPrefix.'PCE_'.$theKey.'###'] = $cObjCode; } } } } } return $markerArray; } /***************************************** * * Emailing * *****************************************/ /** * Sends info mail to user * * @return string HTML content message * @see init(),compileMail(), sendMail() */ function sendInfoMail() { if ($this->conf['infomail'] && $this->conf['email.']['field']) { $fetch = t3lib_div::_GP('fetch'); if ($fetch) { // Getting infomail config. $key= trim(t3lib_div::_GP('key')); if (is_array($this->conf['infomail.'][$key.'.'])) { $config = $this->conf['infomail.'][$key.'.']; } else { $config = $this->conf['infomail.']['default.']; } $pidLock=''; if (!$config['dontLockPid']) { $pidLock='AND pid IN ('.$this->thePid.') '; } // Getting records if (t3lib_div::testInt($fetch)) { $DBrows = $GLOBALS['TSFE']->sys_page->getRecordsByField($this->theTable,'uid',$fetch,$pidLock,'','','1'); } elseif ($fetch) { // $this->conf['email.']['field'] must be a valid field in the table! $DBrows = $GLOBALS['TSFE']->sys_page->getRecordsByField($this->theTable,$this->conf['email.']['field'],$fetch,$pidLock,'','','100'); } // Processing records if (is_array($DBrows)) { $recipient = $DBrows[0][$this->conf['email.']['field']]; $this->compileMail($config['label'], $DBrows, $recipient, $this->conf['setfixed.']); } elseif ($this->cObj->checkEmail($fetch)) { $this->sendMail($fetch, '', trim($this->cObj->getSubpart($this->templateCode, '###'.$this->emailMarkPrefix.'NORECORD###'))); } $content = $this->getPlainTemplate('###TEMPLATE_INFOMAIL_SENT###'); } else { $content = $this->getPlainTemplate('###TEMPLATE_INFOMAIL###'); } } else $content='Error: infomail option is not available or emailField is not setup in TypoScript'; return $content; } /** * Compiles and sends a mail based on input values + template parts. Looks for a normal and an "-admin" template and may send both kinds of emails. See documentation in TSref. * * @param string A key which together with $this->emailMarkPrefix will identify the part from the template code to use for the email. * @param array An array of records which fields are substituted in the templates * @param mixed Mail recipient. If string then its supposed to be an email address. If integer then its a uid of a fe_users record which is looked up and the email address from here is used for sending the mail. * @param array Additional fields to set in the markerArray used in the substitution process * @return void */ function compileMail($key, $DBrows, $recipient, $setFixedConfig=array()) { $GLOBALS['TT']->push('compileMail'); $mailContent=''; $key = $this->emailMarkPrefix.$key; $userContent['all'] = trim($this->cObj->getSubpart($this->templateCode, '###'.$key.'###')); $adminContent['all'] = trim($this->cObj->getSubpart($this->templateCode, '###'.$key.'-ADMIN###')); $userContent['rec'] = $this->cObj->getSubpart($userContent['all'], '###SUB_RECORD###'); $adminContent['rec'] = $this->cObj->getSubpart($adminContent['all'], '###SUB_RECORD###'); reset($DBrows); while(list(,$r)=each($DBrows)) { $markerArray = $this->cObj->fillInMarkerArray($this->markerArray, $r,'',0); $markerArray = $this->setCObjects($userContent['rec'].$adminContent['rec'],$r,$markerArray,'ITEM_'); $markerArray['###SYS_AUTHCODE###'] = $this->authCode($r); $markerArray = $this->setfixed($markerArray, $setFixedConfig, $r); if ($userContent['rec']) $userContent['accum'] .=$this->cObj->substituteMarkerArray($userContent['rec'], $markerArray); if ($adminContent['rec']) $adminContent['accum'].=$this->cObj->substituteMarkerArray($adminContent['rec'], $markerArray); } if ($userContent['all']) $userContent['final'] .=$this->cObj->substituteSubpart($userContent['all'], '###SUB_RECORD###', $userContent['accum']); if ($adminContent['all']) $adminContent['final'].=$this->cObj->substituteSubpart($adminContent['all'], '###SUB_RECORD###', $adminContent['accum']); if (t3lib_div::testInt($recipient)) { $fe_userRec = $GLOBALS['TSFE']->sys_page->getRawRecord('fe_users',$recipient); $recipient=$fe_userRec['email']; } $GLOBALS['TT']->setTSlogMessage('Template key: ###'.$key.'###, userContentLength: '.strlen($userContent['final']).', adminContentLength: '.strlen($adminContent['final'])); $this->sendMail($recipient, $this->conf['email.']['admin'], $userContent['final'], $adminContent['final']); $GLOBALS['TT']->pull(); } /** * Actually sends the requested mails (through $this->cObj->sendNotifyEmail) * * @param string Recipient email address (or list) * @param string Possible "admin" email address. Will enable sending of admin emails if also $adminContent is provided * @param string Content for the regular email to user * @param string Content for the admin email to administrator * @return void * @access private * @see compileMail(), sendInfoMail() */ function sendMail($recipient, $admin, $content='', $adminContent='') { // Admin mail: if ($admin && $adminContent) { if (!$this->isHTMLContent($adminContent)) { $admMail = $this->cObj->sendNotifyEmail($adminContent, $admin, '', $this->conf['email.']['from'], $this->conf['email.']['fromName'], $recipient ); } else { $this->sendHTMLMail($adminContent, $admin, '', $this->conf['email.']['from'], $this->conf['email.']['fromName'], $recipient ); } } // user mail: if (!$this->isHTMLContent($content)) { $this->cObj->sendNotifyEmail($content, $recipient, '', // ($admMail ? '' : $admin), // If the special administration mail was not found and send, the regular is... $this->conf['email.']['from'], $this->conf['email.']['fromName'] ); } else { $this->sendHTMLMail($content, $recipient, '', // ($admMail ? '' : $admin), // If the special administration mail was not found and send, the regular is... $this->conf['email.']['from'], $this->conf['email.']['fromName'] ); } } /** * Detects if content is HTML (looking for tag as first and last in string) * * @param string Content string to test * @return boolean Returns true if the content begins and ends with -tags */ function isHTMLContent($c) { $c = trim($c); $first = strtolower(substr($c,0,6)); $last = strtolower(substr($c,-7)); if ($first.$last=='') return 1; } /** * Sending HTML email, using same parameters as tslib_cObj::sendNotifyEmail() * NOTICE: "t3lib_htmlmail" library must be included for this to work, otherwise an error message is outputted. * * @param string The message content. If blank, no email is sent. * @param string Comma list of recipient email addresses * @param string IGNORE this parameter * @param string "From" email address * @param string Optional "From" name * @param string Optional "Reply-To" header email address. * @return void * @access private * @see sendMail(), tslib_cObj::sendNotifyEmail() */ function sendHTMLMail($content,$recipient,$dummy,$fromEmail,$fromName,$replyTo='') { if (trim($recipient) && trim($content)) { $cls=t3lib_div::makeInstanceClassName('t3lib_htmlmail'); if (class_exists($cls)) { // If htmlmail lib is included, then generate a nice HTML-email $parts = spliti('|',$content,3); $subject = trim($parts[1]) ? trim($parts[1]) : 'TYPO3 FE Admin message'; $Typo3_htmlmail = t3lib_div::makeInstance('t3lib_htmlmail'); $Typo3_htmlmail->start(); $Typo3_htmlmail->useBase64(); $Typo3_htmlmail->subject = $subject; $Typo3_htmlmail->from_email = $fromEmail; $Typo3_htmlmail->from_name = $fromName; $Typo3_htmlmail->replyto_email = $replyTo ? $replyTo : $fromEmail; $Typo3_htmlmail->replyto_name = $replyTo ? '' : $fromName; $Typo3_htmlmail->organisation = ''; $Typo3_htmlmail->priority = 3; // HTML $Typo3_htmlmail->theParts['html']['content'] = $content; // Fetches the content of the page $Typo3_htmlmail->theParts['html']['path'] = ''; $Typo3_htmlmail->extractMediaLinks(); $Typo3_htmlmail->extractHyperLinks(); $Typo3_htmlmail->fetchHTMLMedia(); $Typo3_htmlmail->substMediaNamesInHTML(0); // 0 = relative $Typo3_htmlmail->substHREFsInHTML(); $Typo3_htmlmail->setHTML($Typo3_htmlmail->encodeMsg($Typo3_htmlmail->theParts['html']['content'])); // PLAIN $Typo3_htmlmail->addPlain(''); // SET Headers and Content $Typo3_htmlmail->setHeaders(); $Typo3_htmlmail->setContent(); $Typo3_htmlmail->setRecipient($recipient); // debug($Typo3_htmlmail->theParts); $Typo3_htmlmail->sendtheMail(); } else { debug('SYSTEM ERROR: No HTML-mail library loaded. Set "page.config.incT3Lib_htmlmail = 1" is your TypoScript template.'); } } } /***************************************** * * Various helper functions * *****************************************/ /** * Returns true if authentication is OK based on the "aC" code which is a GET parameter set from outside with a hash string which must match some internal hash string. * This allows to authenticate editing without having a fe_users login * Uses $this->authCode which is set in init() by "t3lib_div::_GP('aC');" * * @param array The data array for which to evaluate authentication * @return boolean True if authenticated OK * @see authCode(), init() */ function aCAuth($r) { if ($this->authCode && !strcmp($this->authCode,$this->authCode($r))) { return true; } } /** * Creating authentication hash string based on input record and the fields listed in TypoScript property "authcodeFields" * * @param array The data record * @param string Additional string to include in the hash * @return string Hash string of $this->codeLength (if TypoScript "authcodeFields" was set) * @see aCAuth() */ function authCode($r,$extra='') { $l=$this->codeLength; if ($this->conf['authcodeFields']) { $fieldArr = t3lib_div::trimExplode(',', $this->conf['authcodeFields'], 1); $value=''; while(list(,$field)=each($fieldArr)) { $value.=$r[$field].'|'; } $value.=$extra.'|'.$this->conf['authcodeFields.']['addKey']; if ($this->conf['authcodeFields.']['addDate']) { $value.='|'.date($this->conf['authcodeFields.']['addDate']); } $value.=$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']; return substr(md5($value), 0,$l); } } /** * Adding keys to the marker array with "setfixed" GET parameters * * @param array Marker-array to modify/add a key to. * @param array TypoScript properties configuring "setfixed" for the plugin. Basically this is $this->conf['setfixed.'] passed along. * @param array The data record * @return array Processed $markerArray * @see compileMail() */ function setfixed($markerArray, $setfixed, $r) { if (is_array($setfixed)) { reset($setfixed); while(list($theKey,$data)=each($setfixed)) { if (!strcmp($theKey,'DELETE')) { $recCopy = $r; $string='&cmd=setfixed&sFK='.rawurlencode($theKey).'&rU='.$r['uid']; $string.='&aC='.$this->setfixedHash($recCopy,$data['_FIELDLIST']); $markerArray['###SYS_SETFIXED_DELETE###'] = $string; $markerArray['###SYS_SETFIXED_HSC_DELETE###'] = htmlspecialchars($string); } elseif (strstr($theKey,'.')) { $theKey = substr($theKey,0,-1); if (is_array($data)) { reset($data); $recCopy = $r; $string='&cmd=setfixed&sFK='.rawurlencode($theKey).'&rU='.$r['uid']; while(list($fieldName,$fieldValue)=each($data)) { $string.='&fD['.$fieldName.']='.rawurlencode($fieldValue); $recCopy[$fieldName]=$fieldValue; } $string.='&aC='.$this->setfixedHash($recCopy,$data['_FIELDLIST']); $markerArray['###SYS_SETFIXED_'.$theKey.'###'] = $string; $markerArray['###SYS_SETFIXED_HSC_'.$theKey.'###'] = htmlspecialchars($string); } } } } return $markerArray; } /** * Creating hash string for setFixed. Much similar to authCode() * * @param array The data record * @param string List of fields to use * @return string Hash string of $this->codeLength (if TypoScript "authcodeFields" was set) * @see setfixed(),authCode() */ function setfixedHash($recCopy,$fields='') { if ($fields) { $fieldArr = t3lib_div::trimExplode(',',$fields,1); reset($fieldArr); while(list($k,$v)=each($fieldArr)) { $recCopy_temp[$k]=$recCopy[$v]; } } else { $recCopy_temp=$recCopy; } $encStr = implode('|',$recCopy_temp).'|'.$this->conf['authcodeFields.']['addKey'].'|'.$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']; $hash = substr(md5($encStr),0,$this->codeLength); return $hash; } /** * Returns true if preview display is on. * * @return boolean */ function isPreview() { return ($this->conf[$this->cmdKey.'.']['preview'] && $this->preview); } /** * Creates an instance of class "t3lib_basicFileFunctions" in $this->fileFunc (if not already done) * * @return void */ function createFileFuncObj() { if (!$this->fileFunc) { $this->fileFunc = t3lib_div::makeInstance('t3lib_basicFileFunctions'); } } /** * If TypoScript property clearCacheOfPages is set then all page ids in this value will have their cache cleared * * @return void */ function clearCacheIfSet() { if ($this->conf['clearCacheOfPages']) { $cc_pidList = $GLOBALS['TYPO3_DB']->cleanIntList($this->conf['clearCacheOfPages']); $GLOBALS['TSFE']->clearPageCacheContent_pidList($cc_pidList); } } /** * Returns an error message for the field/command combination inputted. The error message is looked up in the TypoScript properties (evalErrors.[fieldname].[command]) and if empty then the $label value is returned * * @param string Field name * @param string Command identifier string * @param string Alternative label, shown if no other error string was found * @return string The error message string */ function getFailure($theField, $theCmd, $label) { return isset($this->conf['evalErrors.'][$theField.'.'][$theCmd]) ? $this->conf['evalErrors.'][$theField.'.'][$theCmd] : $label; } } if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['media/scripts/fe_adminLib.inc']) { include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['media/scripts/fe_adminLib.inc']); } ?>