Forums

Problem with PHP code in OnSaveCode

peter49 14 May, 2009
Hi there,

With CF/CC I am building a website containing information on several choirs in our city. For each choir one or more contacts may be registered (users) that I allow to announce concerts and change concerts and other information, but of course only for the choir(s) they have been registered for.
All this has been implemented satisfactorily.
Tables exist (via CF) for choirs and concerts. Heart of the system is a contacts table that contains records each combining a user and a choir. Effectively this implements a many-to-many relation between users and choirs.
When a user visits a choir or concert details page (CC connections) PHP-code uses this table in order to check whether this user is allowed to change this information. If so, an {edit_record} element is presented and via Front Permissions an edit action has been implemented. Works perfectly, great facility!

Now I wish to add to the site a list of recent modifications, being of interest to the general website visitor. Therefore I created a modifications table with fields chg_id (auto-increment), chg_date, chg_author, chg_choir, and chg_action. I wish to add a record upon each user change action. The only place where a user modification becomes real is when the “SAVE” button is clicked during an {edit_record} action. The only place for adding a modification record therefore seems the “OnSaveCode” field under “Front Permissions”. I added there the following code (somewhat generalised for simplicity reasons):

<?php
$choir = "Choir X";
$action = "Some modification";

$localdb =& JFactory::getDBO();
$localusr =& JFactory::getUser();
$localquery = "INSERT INTO `jos_chronoforms_modifications`
         (`chg_date`,`chg_author`,`chg_choir`,`chg_action`) VALUES ('".
         date("Y-m-d H:i:s")."','".$localusr->name."','".$choir."','".$action."')";
$localdb->setQuery($localquery);
$localdb->query();
?>

The SAVE button still works perfectly, but no modification record is ever added. Debug output via echo statements cannot be made visible. How can I check that this code is really executed? Is it, anyway? Making a deliberate programming error has no noticeable influence on the result. The code itself seems correct. When I place it in “Record Edit Template” a modification record is added each time a valid user enters the {edit_record} page. Not what I want of course, but just to prove that the code is working.

Any bright ideas?

Curious greetings,
Peter
GreyHead 22 May, 2009
Hi Peter,

Did you get this fixed?

It's been in my pending list for a week now. I don't see anything wrong with your code.

OK - just checked the ChronoConnectivity code and I think that there's a bug. Open chronoconnectivity.php and look for this line around line 307
		eval('?>'.$connections[0]->OnSaveCodefront);
and replace it with this
		eval('?>'.$connection->OnSaveCodefront);


Bob
peter49 22 May, 2009
Hi Bob,

NumberOfBugs--; // Bingo !!

The bug was understandable (as usual with hindsight), given the foregoing code in the CC code, but effectively prohibited execution on the OnSaveCode part! Thank you for your answer, the week on your problem stack was well spent!
I had not fixed the problem, but had found a way around it. The result however was that the modification record was not created at the time of the modification itself, with the risk of loss of information. Clearly I had a requirement for the OnSaveCode part for the most natural solution.
I'll have to spend some effort now to restructure my software to the most favourable solution (with pleasure!). Maybe you can help me with one problem that exposes itself only now.
In the Record Edit Template the record-to-be-edited is shown via <input name="fieldname" ...> elements. I found that upon OnSaveCode this data is no longer accessible that way, but I do need it there! After inspection of the CC code I discovered a possibility to access it via $_POST['fieldname']. Is that the only way or could you suggest a better one?

Regards,
Peter
GreyHead 23 May, 2009
Hi Peter,

The OnSave Code is simple evaluated - there is no place-holder replacement.

The best way to get the $_POST info in Joomla 1.5 is to use the JRequest methods like
$field_name = JRequest::getVar('field_name', 'default', post');
The JRequest methods pass the submitted value through some filters to remove any dangerous code submission. You can also replace getVar with getInt, getString and a few other values to add type validation and set 'post' to 'get', 'cookie' or '' to filter the source.

In combination there are some valuable security protections here and I try to make a habit of using them - though $_POST['field_name'] will still work OK.

Bob
peter49 24 May, 2009
Hi Bob,

thanks again for your answer, valuable information (your answer to my other thread looks like a Solomon judgement...).
One problem, related to OnSaveCode, is still keeping me busy. Maybe I should open a new thread for it, but as is is so related to the foregoing I decided not to do so.
Some background: On my site I have a CC-generated list of choir summaries. Each summary line contains a link to another CC item, being a detailed overview of the selected choir. Somewhere on this forum I found a technique for doing so. The link looks like
<a href="index.php?option=com_chronoconnectivity&connectionname=Choir_details + &Choir_selector={cf_id}">{choir_name}</a>

The syntax is not completely clear to me, but I understand that some kind of parameter is dynamically created. The corresponding WHERE SQL part in connection Choir_details (on the same Choirs table) is
WHERE cf_id="<?php echo JRequest::getVar('Choir_selector') ; ?>"

The parameter is retrieved and the query results in the selected choir only. Works perfectly.
This connection contains the {edit_record} item, shown only to selected users. The very last lines of chronoconnectivity.php contain the redirects after "SAVE" and "CANCEL", of course without the parameter setting, fair enough. And here's my problem: I am looking for some trick to make the redirect generate the page for the originally selected choir. As the parameter is gone, I can test for that and act accordingly, but whatever I try - no luck. I tried e.g.
WHERE `cf_id`="
<?php
static $myselection;
$p0 = JRequest::getVar('Choir_selector');
/* If ($p0) the parameter is set in my own link 
   else we come from the redirect in chronoconnectiviy.php
   and we hope the old value of $myselection is still valid...
*/
if ($p0) $myselection = $p0;
echo $myselection;
?>"

Also I tried to change "static" into "global". Nope.
Another attempt: use JRequest::setVar and getVar on $myselection, even with different $hash values. Nope again.
In all cases the primary choir details page is shown correctly, but after redirect an empty page is the only result.
Should I abandon all hope?

Regards,
Peter
GreyHead 26 May, 2009
Hi Peter,

I think I'm following this . . .

The first thing that you need to do is to make sure that the Choir Id is in the Edit form - I usually display it in a text field i.e. non-editable and add it to a hidden field so that I can access it.

The next step is a definite fudge but might just work. At the end of the OnSave code add this:
<?php
$cf_id = JRequest::getInt('cf_id');
$connection->name .= "&cf_id=".$cf_id
?>
This changes the connection name to include the value but as far as I can see it's only used in the links at this stage.

Bob
peter49 26 May, 2009
Hi Bob,

yes, you followed it, and yes, your suggestion works, be it after a small correction. It should read:
<?php
$cf_id = JRequest::getInt('cf_id');
$connection->name .= "&Choir_selector=".$cf_id
?>

It has been told at other places in this forum: you are a genious. But calling this trick a fudge (I did know the word, but - until now - not this meaning) seems to me the understatement of the year! Currently in chronoconnectivity.php the code for file uploads is outcommented. When it will ever be reused in a next version the above solution will run into a disaster. And you (at least I) never know what else might be done with the connection name until the redirect is executed. Ok, I asked for it, but in my view this solution is just too dangerous.

In the meantime I found another solution myself. The parameter value can be stored in a file (necessarily one for each user!) and retrieved upon return from the redirect. Drawbacks: a lot more overhead (a file is written each time some user asks for a choir detail page), and upon return I can't differentiate between SAVE and CANCEL buttons. But also less dangerous in my view (but you may disagree!). Here's my solution, code to be placed at "WHERE SQL" in General:
WHERE `cf_id`="
<?php
$myusr =& JFactory::getUser();
$fname = 'choices/choir-'.$myusr->username.'.txt';
$choice = JRequest::getVar('Choir_selector');
if ($choice) {
// Comes from my own link, store for later usage
  $fx = fopen($fname,'w');
  fwrite($fx, $choice);
  fclose($fx);
} else {
// Empty: results from redirect, retrieve saved value
  $fx = fopen($fname,'r');
  $choice = fgets($fx);
  fclose(fx);
}
echo $choice;
?>"


Better or worse?

Regards,
Peter
GreyHead 26 May, 2009
Hi Peter,

Yes, your solution is a lot more elegant - and safer - than mine. One improvement would be to save the info in the User Session (or possibly a cookie) to save all that file handling.
WHERE `cf_id`="
<?php
$myusr =& JFactory::getUser();
$session =& JFactory::getSession();

$choice = JRequest::getVar('Choir_selector');
if ($choice) {
  // Comes from my own link, store for later usage
  $session->set('choice', $choice);
} else {
  // Empty: results from redirect, retrieve saved value
  $choice = $session->get('choice', '');
}
echo $choice;
?>"

Bob

Later: added missing semicolon
peter49 26 May, 2009
Hi Bob,

absolutely perfect! (apart from the missing semicolon)
It has been implemented already and all goes well. I didn't know about the session object, but it enables a perfect solution for this problem. Thank you very much for your advice and the fruitful cooperation, that clearly demonstrated 1 + 1 > 2.
Finally, as a kind of "thank you", you may find time to read http://www.pbm.com/~lindahl/real.programmers.html. A nice and humorous story from the "old" computer days with a giant wink.

Regards
Peter
GreyHead 29 May, 2009
Hi Peter,

Great article - I started my coding with Fortran on a card punch so it brought back some memories (mostly bad)!

Bob

PS I fixed the semi-colon in my earlier post in case someone else uses the code.
This topic is locked and no more replies can be posted.