Posts tagged ‘PHP’

jQuery AJAX & Internet Explorer

Internet Explorer getJSON trouble

This piece of code initially did not work for me on IE:

$.getJSON(“../inc/exercise_ajax.php?” + $(this).serialize(), function(json)

FireFox worked without problems.

The reason is that my JSON code was not well-formed. It had a comma (‘,’) too much.

Here’s the code which I use in PHP to create my JSON (braces omitted):

foreach($answers as $question => $answer){
$outstr .= ‘”q’.$question.’”: ‘;
if (isset($_GET[$question])){
if ($_GET[$question] == $answer) $outstr .= ‘true’;
else $outstr .= ‘false’;
} else $outstr .= ‘null’;
$outstr .= ‘,’;
}
echo chop($outstr,’,');

You have to chop off the trailing comma – if you don’t, IE will choke on it and your callback function won’t be executed.

Internet Explorer & AJAX caching

Yes, Internet Explorer caches your requests. You’ve got to empty the browser cache before testing the fix I mentioned. Also, you should append a unique parameter to suppress caching, i.e. the current timestamp. Example:

var now = new Date();
// submit with AJAX
$.getJSON(“../inc/exercise_ajax.php?ts=” + now.getTime() + ‘&’ + $(this).serialize(), function(json)

Adding content to the head of Lectora HTML output

There’s the possibility to add an “external HTML object”. If you choose “header scripting”, your content would be added to the <script> section of Lectora in the header. In most cases that’s not what you want to achieve. There’s another strange option “Top of file scripting” which simply inserts your content just before the <!DOCTYPE> tag. The only use I can see for this is for PHP scripting which needs to be done before any output was sent to the browser (i.e. header modification).

What you want to choose to include arbitrary content to the <HEAD> section of Lectora generated HTML documents is the “META Tag” option. Unfortunately, this does not allow to include external .txt files, so you have to paste your code in Lectora’s input window. (You would have needed to update the .txt file anyways, as Lectora stays with the initial .txt file version instead of updating it from the hard disk every time. That way it’s not really a big loss that you can’t use .txt files.)

And there IS a way to include a file’s contents in the header. Just drop a PHP file somewhere on your server and include it using the following as a “meta tag”:

<?php include(‘your/path/to/header.php’);?>

Adding aliases to Concrete5 pages programmatically.

Suppose, you want to provide legacy URLs when porting the page to a new version. I need to do this, as I am writing the IdeaDay Import Wizard.

An example:

  • The new page will be under /my/new/page
  • You want a legacy alias under /legacy_path/legacy_name

There is a function $page->addCollectionAlias($c); which will alias your Collection UNDER another Collection (essentially adding the page with the same name elsewhere). We could use this, but would need to work around the new page’s name and cHandle (which will change: page != legacy_name)

How does C5 handle this internally, when editing page aliases?

/concrete/startup/process.php contains the code (look for else if ($_POST['update_metadata']) and continue to read).

It essentially sets $data['ppURL'] to the aliases (new AND old), and uses $page->update($data);

There is one important thing to consider: to add a new path, the key needs to be a string! This had me baffled for one hour.

So, the entire code to add one new alias, AND keep all the old ones will be:

$this_page_paths = $in_pg->getPagePaths();
$new_paths = array();
foreach($this_page_paths as $path){
if (!$path['ppIsCanonical']) {
$new_paths[$path['ppID']] = $path['cPath'];
}
}
$new_paths['add_path'] = $add_alias;
$data = array();
$data['ppURL'] = $new_paths;
$in_pg->update($data);

$in_pg is the page you want to add the alias to. It is important that you check for the path being canonical, else your main page path will be overwritten (and the page will be redirecting to /). The new path ($add_alias) is added with a string (it does not matter which string you use).

We could use rescanPagePaths to do it directly, but we should not: update fires on_page_update events, for instance.

Now to the second part: modifying .htaccess to provide compatibility.

RewriteRule ^(.*)\.phtml(.*)$ $1$2 [L]

By adding this rule you will be stripping out .phtml from your links -> thus, compatibility with the following path from our example would be preserved:

/legacy_path/legacy_name.phtml

This rewriting is necessary, as Concrete does not allow dots (.) in page paths – it replaces them by an underscore.

Concrete5 errors

Fatal error: Class ‘CollectionAttributeKey’ not found in (…)/concrete/models/collection.php on line 183

This class is defined in concrete5.3.3.1\concrete\models\attribute\categories\collection.php

The problem is easily resolved by loading the appropriate model in your code:

Loader::model(‘attribute/categories/collection’);

Concrete5 :: interacting with the database

The C5 API has a class Database in the core package (libraries/database.php). Alas, this is not the documentation we’re looking for (we’re looking for query, etc. methods, which are not present there).

Actually the methods used come directly from the included ADODB librarary. You can download a documentation here.

Usage:

//Load the Database Layer.
$db = Loader::db();
//quote the string we’ll be inserting (use get_magic_quotes_gpc() as second parameter to avoid double escaping!)
$source = $db->qstr($source, get_magic_quotes_gpc());
$content = $db->qstr($content);
$sql = “insert into IdImportWizardSources (source, content) “;
$sql .= “values ($source,$content)”;
if ($db->Execute($sql)===false) {
//error handling
echo ‘error inserting: ‘ .$db->ErrorMsg();
}

FormHelper select

Not understanding the Concrete 5 API comment on the select function of the Form Helper, I looked into the source:

/**
* Renders a select field. First argument is the name of the field. Second is an associative array of key => display. Second argument is either the value of the field to be selected (and if it’s blank we check post) or a misc. array of fields
* @param string $key
* @return $html
*/
public function select($key, $values, $valueOrArray = false, $miscFields = array())

Select builds a SELECT Dopdown with OPTIONS. That much I already understood from the API.

Here’s my explanation of the parameters passed in to select:

  • $key: the name of the element to be created.
  • $values: an array of options, stored as $k=>$value. Used like this:
    ‘<option value=”‘ . $k . ‘” ‘ . $selected . ‘>’ . $value . ‘</option>’;
  • $valueOrArray: this can either be set to the default value to be selected (use the option value, not the displayed text between the tags) OR it can be an array and is used as the array to populate $miscFields (see explanation there), omitting the default value. A bit unusual perhaps, probably it’s a timesaver when you code these forms a lot.
  • $miscFields: An associative array ($k => $value): insert additional keys into the tag (i.e. multiple=”multiple”

The fun in using select is, it STORES your settings between sessions. Boy, I should have used it earlier, when hand-coding this for other parts of the project.

Another note on ValidationErrorHelper:

/**
* Returns whether or not this error helper has more than one error registered within it.
* @return bool
*/
public function has() {
return (count($this->error) > 0);
}

As one can read from the source above, the Validation Helper returns whether there are errors (even if it is only one) or there are none!

Server Management Software

Wir sind dazu bereit, den nächsten Schritt zu gehen und die Verwaltung des Webservers von manuell auf semi-manuell umzustellen.

Unser Mailsystem wird nach wie vor vom Websystem abgekoppelt laufen – auf Zimbra-Basis.

Für den Webserver selber rüsten wir eine Server Management Software nach. Sie muß einen typischen LAMP Server unterstützen (Linux – Debian / Apache / MySQL / PHP)

Hier sind die Kandidaten:

  1. SysCP

    Gut dokumentiert, aktive Community, interessanter Funktionsumfang (inklusive Resellern die ihre Kunden selbst administrieren können usw.), deutsches User Interface verfügbar.

    Natürlich Open Source.

  2. Kloxo / HyperVM

    Interessant für unser Setup (OpenVZ, mehrere VPMs, …); allerdings evtl. nur auf englisch und massiver Overkill. Es heißt, dass es als Open Source released wurde, jedoch ist auf der Firmenseite etwas von Lizenzkosten die Rede …

  3. http://www.virtualmin.com/

    Virtualmin ist eine weitere Möglichkeit. Hier sticht ebenfalls keine Sprachunterstützung heraus, das System ist komplex und deckt z.B. detaillierte CPU Leistung usw. Statistiken ab.

    Unterstützt einen hohen Grad von Sicherheit bei PHP – die Prozesse werden unter dem jeweiligen User ausgeführt, mit suexec und mod_fastcgi. Siehe auch: http://en.wikipedia.org/wiki/Webmin

  4. OpenLSM

    Eine indische Software mit einer schönen, aber leider nicht so informativen Webseite. In der Feauture Liste schaut das Produkt gut aus – Anlegen von Resellern, Monitoring, … Unterstützt auch Subversion.

  5. VHCS

    Obwohl auf anderen Seiten behauptet wird, dass das Projekt tot sei, ist es nicht so. Die Jungs arbeiten gerade an Release 2.6, der Web 2.0 in VHCS bringen soll. Das Interface schaut übersichtlich und aufgeräumt aus.

  6. OpenPanel

    Schaut sehr, sehr gut aus – ein JavaScript zentriertes UserInterface. Leider ist es seit Juli 2008 in Beta 0.9.5 stehen geblieben. Eine 1.0 steht fast vor der Tür – sie wird Debian 5.0 unterstützen. Definitiv einen Blick wert – auch wenn es erstmal nur in Englisch ist.
    Wird von  PanelSix entwickelt, hier ist die Doku.

Hier ist noch ein Überblick auf Wikipedia (EN).

MySQL

[25-Feb-2010 16:15:46] PHP Warning: mysql_real_escape_string() [<a href='function.mysql-real-escape-string'>function.mysql-real-escape-string</a>]: Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (2) in … on line 38
[25-Feb-2010 16:15:46] PHP Warning: mysql_real_escape_string() [<a href='function.mysql-real-escape-string'>function.mysql-real-escape-string</a>]: A link to the server could not be established in … on line 38
(…)

Lösung des Problems:
die Funktion mysql-real-escape-string erfordert eigentlich zwei Parameter: zuerst den $unescaped_string, dann die resource $link_identifier. Lässt man zweiteres weg, versucht MySQL die aktuell zuletzt geöffnete Verbindung zu benutzen.

Ich habe in meinem Skript den Zugang zur Datenbank erst danach geöffnet. (Das ist der wichtigste Unterschied zwischen mysql_escape_string und mysql_real_escape_string – ersteres erfordert KEINEN Zugriff auf die Datenbank!)