Potablog 1338.at Header

 
I was searching for solutions for using my existing iCal-calendars from Lightning/Sunbird with my new HTC Desire WITHOUT using the Google-calender (respectively without sending them your private data).

To create the calendars on the Adroid I couldn't find any other way then, just to create them at your Google-Account, sync them and afterwards disable the calendar-syncing at your Android-Phone.

Now you have to install yourself a CalDav-Server. The simplest server I found, for configuring and installing was SabreDav. Just get a XAMPP running on your machine and installing SabreDav.

Since there is no out-of-the-box possibility to import your iCal-files in the new CalDav server I wrote myself a little script, that does that for me. I know the code is messy and very imperformant, but it works and that is all it counts for me, at the moment.

Code
<?php
/* iCal-import script for SabreDav CalDav Server
* Coder: Daniel Bomze - daniel.bomze {att} gmx {dottt} net
* Last changes: 04.01.2011
* Please let me know if you find bugs, failures or just have code-improvements
*/

//the user in which the calendars should be created, the have to exists and start with 'pricipals/'
$principalUser = "principals/admin";

// settings
date_default_timezone_set('Europe/Berlin');

// If you want to run the SabreDAV server in a custom location (using mod_rewrite for instance)
// You can override the baseUri here.
// $baseUri = '/';

/* Database */
$pdo = new PDO('sqlite:data/db.sqlite');
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);

//Mapping PHP errors to exceptions
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");

// Files we need
require_once 'lib/Sabre/autoload.php';

// The object tree needs in turn to be passed to the server class
$server = new Sabre_CalDAV_Server($pdo);

if (isset($baseUri))
$server->setBaseUri($baseUri);

$backend = new Sabre_CalDAV_Backend_PDO($pdo);
$calendars = $backend->getCalendarsForUser($principalUser);
foreach($calendars as $calendar){
$calendars[$calendar["uri"]] = $calendar;
}
$dir_handle = opendir(".");
$calendar_options = array("VEVENT","VTODO", "{DAV:}description" => "");
$prepend_data = "BEGIN:VCALENDAR
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
VERSION:2.0
";
$append_data = "
END:VCALENDAR
";
while($file = readdir($dir_handle)){
if(strrchr($file, ".") == ".ics"){
$calendar_uri = substr($file, 0, strrpos($file, "."));
$calendar_options["{DAV:}displayname"] = $calendar_uri;
if(!array_key_exists($calendar_uri, $calendars)){
$calendar_id = $backend->createCalendar($principalUser, $calendar_uri, $calendar_options);
}
else{
$calendar_id = $calendars[$calendar_uri]["id"];
}
$ics_file = file_get_contents($file);

$count_matches = preg_match_all("/(BEGIN\:VEVENT)+?(.*?)(END\:VEVENT)+?/is",$ics_file, $matches,PREG_SET_ORDER );
foreach($matches as $match){
$UID = trim(preg_replace("/(.*?)\sUID:(.*?)\n(.*)/ims", "$2", $match[0])).".ics";
$date = preg_replace("/(.*?)\sLAST-MODIFIED:(.*?)\s(.*)/ims", "$2", $match[0]);
$unixtimestamp = mktime(substr($date,9,2), substr($date,11,2), substr($date,13,2), substr($date,4,2), substr($date,6,2), substr($date,0,4));
$calendar_obj = $backend->getCalendarObject($calendar_id, $UID);
if($calendar_obj === FALSE){
$backend->createCalendarObject($calendar_id, $UID, $prepend_data.$match[0].$append_data);
}
else{
if($calendar_obj["lastmodified"] <= $unixtimestamp){
$backend->updateCalendarObject($calendar_id, $UID, $prepend_data.$match[0].$append_data);
}
else{
//entry in online-calender is newer than the one in ics-file, so do not update it
}
}

}
}
}
echo "all files were imported";
?>




Just put this code in a file in the directory where your SabreDav-Server is located and put the .ics files in the same directory.

You eventually need to increase the max_execution_time in the php.ini file
A value of 600 worked fine for me.

If your iCal-files were imported to your CalDav serer you can synchronize the your Android phone with the server. To synchronize your Android calendar with your new CalDav-Server you will have to install this tiny app: Calendar (CalDAV) Sync

When configuring the app on your phone your URL to the calendar could look like this

Codehttp://192.168.0.1/dav/calendarserver.php/calendars/admin/Privat/


Also you can access the CalDav server via Lightning/Sunbird via:
New calendar->On the network->select CalDav and enter the URL to your calender. Don't forget the trailing slash! For me the URL looked for example like this
Codehttp://192.168.0.1/dav/calendarserver.php/calendars/admin/Privat/


Explaination:
192.168.0.1 is the IP of the computer where der xampp is runing,
dav is the directory where I installed my SabreDav server,
calendarserver.php is the SabreDav calendar-server file.
calendars, the virtual directory calandars is for accessing (who got it? ;-)) the calendars,
admin is the principal/user and
Privat is the name of the calandar as i created it.
Be sure to have the trailing slash at the end of the URL or this won't work properly.

Tip: If you wan't to synchronize your phone from outside the LAN you have to use a VPN or a public webserver.

If you have questions feel free to contact me via comments, email or jabber.

Update:
Added the trim() function to the UID-detection, because if synchronizing without them, apache sometimes can't find the ics-files.
Direktlink  Kommentare: 10 geschrieben von potassium am Dienstag, 04.01.2011, 14:36


Just to remember the next time...
Direktlink  Kommentare: 0 geschrieben von potassium am Mittwoch, 29.09.2010, 21:09
Eingeordnet unter: PHP-Entwicklung, Programmieren


Die PHP-Funktion empty() gibt Auskunft darüber, ob die angegebe Variable leer ist. Folgendes weiß das Manual dazu zu sagen
ZitatReturns FALSE if var has a non-empty and non-zero value.

The following things are considered to be empty:
"" (an empty string)
0 (0 as an integer)
"0" (0 as a string)
NULL
FALSE
array() (an empty array)
var $var; (a variable declared, but without a value in a class)


Man sollte nun doch meinen, dass folgende beide Code-Snippets das gleiche Ergebnise erzeugen: nämlich true.
Code
<?php
$var = "0";
var_dump(empty($var));
?>

Code
<?php
$var = "00";
var_dump(empty($var));
?>

Dem ist aber nicht so.
Das erste snippet gibt folgendes wiede
Zitatbool(true)

das zweite Snippet
Zitatbool(false)


Um darauf zu kommen, habe ich gerade zwei Stunden meines Lebens verschwendet...Dankeschön!
Direktlink  Kommentare: 4 geschrieben von potassium am Donnerstag, 19.08.2010, 22:06
Eingeordnet unter: PHP-Entwicklung, Programmieren


When serialize()ing an array containing the data of the last created blogpost there was no error at first.
But if the data were fetched from the database and the script tried to unserialize() them the following error occured:
ZitatNotice: unserialize() [function.unserialize]: Error at offset 51 of 66 bytes in somefile.php

So why is this?
Lets say you have an array with 3 indizes containing 2 strings and one integer.

Code$somearray[0] = "test";
$somearray[1] = "he hasn\'t eaten anything";
$somearray[2] = 36;

As you can see the single quote in the second array-element is escaped by a backslash.
If you now serialize the data you get the following string
Codea:3:{i:0;s:4:"test";i:1;s:25:"he hasn\'t eaten anything";i:2;i:36;}

If this string is now written to the database the backslashes disappears and the field contains the following data:
Codea:3:{i:0;s:4:"test";i:1;s:25:"he hasn't eaten anything";i:2;i:36;}

As the considerate reader might have discovered the length of the highlighted string was first 25 characters and is after inserting into the database 24 characters long.
So if PHP tries to unserialize the string it thinks it has to read 25 characters but there are only 24. This throws the above error.

So how can you circumvent this?
Code$somearray[0] = "test";
$somearray[1] = "he hasn\'t eaten anything";
$somearray[2] = 36;
foreach($somearray as $key=>$value){
$somearray[$key] = stripslashes($value);
}
$serialized_data = addslashes(serialize($somearray));


So the backslashes are removed before serializing the data and added afterwards to prevent database malfunctions or errors.
Direktlink  Kommentare: 0 geschrieben von potassium am Donnerstag, 27.08.2009, 22:33


Bwah, derzeit arbeite ich grad am Release 2.0 von PotaBlog. Da sich einige Dinge grundlegend verändern, ist es ein weitaus größerer Aufwand, als erwartet.

Bin gerade 3 Stunden gesessen und hab nur Texte aus Templates in Variablen kopiert und diese Texte ins Englische übersetzt -_-

Wünsche eine gute Nacht!
Direktlink  Kommentare: 0 geschrieben von potassium am Freitag, 03.04.2009, 03:55


Da ich für ein Projekt Barcodes der Form Interleaved 2 of 5 brauche und die Schriftarten dafür erst ab 139 $ zu bekommen sind hab ich beschlossen das mit PHP und GD-Library selbst zu lösen.

Mit Hilfe von Nick Johnsons Site über Barcodes und spezifisch über I2O5 war es möglich das zu bekommen, was ich erreichen wollte:

Die Zahl 0930000153 wird umgewandelt in
Picture

Und sieht auch noch aus wie das Original, das ich nachzumachen versuchte.

Gelöst hab ich es wie folgt:
Die umzuwandelnde Zahl wird in 2 Zeichen lange Strings aufgespalten und diese in ein Array geschrieben. In einem anderen Array, dass 2 Indizes hat [0-9] und [0-4] steht jeweils drinnen ob es als ein breiter oder ein dünner Strich dargestellt werden soll - nach folgendem Schema.
Code0: nnwwn
1: wnnnw
2: nwnnw
3: wwnnn
4: nnwnw
5: wnwnn
6: nwwnn
7: nnnww
8: wnnwn
9: nwnwn

Wobei n für narrow als dünn und w für wide also dick steht.
Nun wird eine Schleife gestartet die von 0 bis 4 durchläuft und dabei wird der die erste Ziffer der 2 Ziffern die vorher in ein Array geschrieben wurden als Index genommen und die Schleifenzähler-Variable für den 2 Index.
Dann wird je nach Inhalt des 2. Arrays entweder ein dünner Senkrechter Strich, ein dünner Abstand, ein dicker Strich oder ein dicker Abstand in das Bild geschrieben.
Mit der 2. Zahl wird danach ebenso fortgefahren.

Code//create image
$width = "300";
$height = "40";
$img = ImageCreatetruecolor($width, $height) or die("Cannot Initialize new GD image stream");
if(!$img){
die("can't create picture");
}
$black = imagecolorallocate($img, 0, 0, 0);
$white = imagecolorallocate($img,255,255,255);
imagefill($img,0,0,$white);
$data = str_split("0930000153",2);
global $pos;
$pos = 1;
//startpattern
nline();
nspace();
nline();
nspace();
//eigentliche Daten
foreach($data as $data){
for($i=0;$i<=4;$i++){
call_user_func($digits[$data[0]][$i]."line");
call_user_func($digits[$data[1]][$i]."space");
}
}
//endpattern
wline();
nspace();
nline();
//show image
Header("Content-Type: image/png");
imagepng($img);
imagedestroy($img);
exit();

Wobei im Array $digits halt noch die o.g. Daten drinnenstehn.
Hoffe alle Unklarheit ist beseitigt.

Direktlink  Kommentare: 0 geschrieben von potassium am Montag, 23.02.2009, 18:41


Da PotaBlog nun in Version 1.70 released ist, sind Kommentare ab sofort auch wieder möglich.
Direktlink  Kommentare: 0 geschrieben von potassium am Freitag, 26.09.2008, 01:28


Ab PHP Version 5.2 wurde die Funktion setcookie() erweitert um das Argument [, bool $httponly ]
Nun lautet die Funktion
Code
bool setcookie ( string $name [, string $value [, int $expire [, string $path [, string $domain [, bool $secure [, bool $httponly ]]]]]] )

httponly bewirkt, dass beim Senden des Cookies an den Browser ein httpOnly; mitgesendet wird, das bei neuen Browsern verhindert, dass das Cookie von Javascript oder anderen Clientseitigen Skriptsprachen gelesen wird.

Es funktionert derzeit bei folgenden Browsern:

Microsoft Internet Explorer 6 (SP1)+ Yes
Mozilla Firefox 2.0.0.6 Yes
Netscape Navigator 9.0b3 Yes
Opera 9.23 No
Opera 9.50 Yes
Safari 3.0 No
Google's Chrome Beta (initial public release) Yes
(Verhindert jeweils nur das lesen)

Mehr dazu hier, hier und hier.

Was macht man aber nun, wenn man eine PHP-Version vor 5.2 benutzt und sich nicht selbst eine setcookie() Funktion basteln will bzw. die Header manuell senden?

Ganz einfach: Man fügt an das die Variable $domain einfach
Code; httpOnly;

an.

Das sieht dann zb so aus
Codesetcookie("userid", $userid, (time() + 886400), "/", $_SERVER["SERVER_NAME"]."; httpOnly;", FALSE);


Der Browser erhällt dann folgenden Header

CodeSet-Cookie: userid=5; expires=Wed, 01-Oct-2008 04:20:40 GMT; path=/; domain=localhost; httpOnly;


Was exakt der Ausgabe von der setcookie() Funktion in PHP ab Version 5.2 entspricht.
Ein wenig Dirty aber es funktioniert :-)


Direktlink  Kommentare: 0 geschrieben von potassium am Sonntag, 21.09.2008, 00:07