diff --git a/carddav2fb.php b/carddav2fb.php index ac1563dd..ff3ea630 100644 --- a/carddav2fb.php +++ b/carddav2fb.php @@ -28,9 +28,9 @@ require_once('lib/fritzbox_api_php/fritzbox_api.class.php'); if ($argc == 2) { - $config_file_name = $argv[1]; + $config_file_name = $argv[1]; } else { - $config_file_name = __DIR__ . '/config.php'; + $config_file_name = __DIR__ . '/config.php'; } // default/fallback config options @@ -42,10 +42,10 @@ $config['usb_disk'] = ''; if(is_file($config_file_name)) { - require($config_file_name); + require($config_file_name); } else { - print 'ERROR: No '.$config_file_name.' found, please take a look at config.example.php and create a '.$config_file_name.' file!'.PHP_EOL; - exit(1); + print 'ERROR: No '.$config_file_name.' found, please take a look at config.example.php and create a '.$config_file_name.' file!'.PHP_EOL; + exit(1); } // --------------------------------------------- @@ -79,14 +79,14 @@ class CardDAV2FB { - - protected $entries = array(); - protected $fbxml = ""; - protected $config = null; - - public function __construct($config) { - $this->config = $config; - } + + protected $entries = array(); + protected $fbxml = ""; + protected $config = null; + + public function __construct($config) { + $this->config = $config; + } // Source: https://php.net/manual/de/function.tempnam.php#61436 public function tempdir($dir, $prefix='', $mode=0700) { @@ -101,367 +101,367 @@ public function tempdir($dir, $prefix='', $mode=0700) { return $path; } - public function base64_to_jpeg( $inputfile, $outputfile ) { - /* read data (binary) */ - $ifp = fopen( $inputfile, "rb" ); - $imageData = fread( $ifp, filesize( $inputfile ) ); - fclose( $ifp ); - /* encode & write data (binary) */ - $ifp = fopen( $outputfile, "wb" ); - fwrite( $ifp, base64_decode( $imageData ) ); - fclose( $ifp ); - /* return output filename */ - return( $outputfile ); - } - - public function get_carddav_entries() { - $entries = array(); - - // format output of messages (info, debug, error) - $message_info = "[\033[32m INFO \033[0m] "; - $message_successful = "[\033[32m OK \033[0m] "; - $message_debug = "[\033[36m DEBUG \033[0m] "; - $message_error = "[\033[31m ERROR \033[0m] "; - - // perform an ftps-connection to copy over the photos to a specified directory - $ftp_server = $this->config['fritzbox_ip_ftp']; - $conn_id = ftp_ssl_connect($ftp_server); - ftp_set_option($conn_id, FTP_TIMEOUT_SEC, 60); - $login_result = ftp_login($conn_id, $this->config['fritzbox_user'], $this->config['fritzbox_pw']); - ftp_pasv($conn_id, true); + public function base64_to_jpeg( $inputfile, $outputfile ) { + /* read data (binary) */ + $ifp = fopen( $inputfile, "rb" ); + $imageData = fread( $ifp, filesize( $inputfile ) ); + fclose( $ifp ); + /* encode & write data (binary) */ + $ifp = fopen( $outputfile, "wb" ); + fwrite( $ifp, base64_decode( $imageData ) ); + fclose( $ifp ); + /* return output filename */ + return( $outputfile ); + } + + public function get_carddav_entries() { + $entries = array(); + + // format output of messages (info, debug, error) + $message_info = "[\033[32m INFO \033[0m] "; + $message_successful = "[\033[32m OK \033[0m] "; + $message_debug = "[\033[36m DEBUG \033[0m] "; + $message_error = "[\033[31m ERROR \033[0m] "; + + // perform an ftps-connection to copy over the photos to a specified directory + $ftp_server = $this->config['fritzbox_ip_ftp']; + $conn_id = ftp_ssl_connect($ftp_server); + ftp_set_option($conn_id, FTP_TIMEOUT_SEC, 60); + $login_result = ftp_login($conn_id, $this->config['fritzbox_user'], $this->config['fritzbox_pw']); + ftp_pasv($conn_id, true); $tmpdir = $this->tempdir($this->config['tmp_dir']); - foreach($this->config['carddav'] as $conf) { - $carddav = new carddav_backend($conf['url']); - $carddav->set_auth($conf['user'], $conf['pw']); - $xmldata = $carddav->get(); - - // convert everything to utf-8 (for OpenXchange/Appsuite) - //$xmldata = utf8_encode($xmldata); - - // DEBUG: writes an XML-file of the addressbook to the server from where the script is executed - /* - $filename = $conf['user']."_".basename($conf['url']) . ".xml"; - print PHP_EOL."Save whole addressbook as xml file: ".$filename; - file_put_contents($filename, $xmldata); - */ - - // read raw_vcard data from xml response - $raw_vcards = array(); - $xmlvcard = new SimpleXMLElement($xmldata); - - foreach($xmlvcard->element as $vcard_element) - { - $id = $vcard_element->id->__toString(); - $value = (string)$vcard_element->vcard->__toString(); - $raw_vcards[$id] = $value; - } - - // parse raw_vcards - $result = array(); - foreach($raw_vcards as $v) { - $vcard_obj = new vCard(false, $v); - - // name - $name_arr = $vcard_obj->n[0]; - $name = $this->_concat($this->_concat($name_arr['LastName'],$name_arr['FirstName']),$name_arr['AdditionalNames']); - - // if name is empty we take organization instead - if(empty($name)) { - $name_arr = $vcard_obj->org[0]; - $name = $name_arr['Name']; - } - - // format filename of contact photo; remove special letters - if ($vcard_obj->photo) { - $photo = str_replace(array(',','&',' ','/','ä','ö','ü','Ä','Ö','Ü','ß','á','à','ó','ò','ú','ù','í'), - array('','_','_','_','ae','oe','ue','Ae','Oe','Ue','ss','a','a','o','o','u','u','i'),$name); - } else { - $photo = ''; - } - - // phone - $phone_no = array(); - if ($vcard_obj->categories) { - $categories = $vcard_obj->categories[0]; - } else { - $categories = array(''); - } - - // e-mail addresses - $email_add = array(); - - // retrieve photos, save them as jpg and put them via ftp to the FRITZ!Box - if ($vcard_obj->photo) { - // get photos, rename and save as xml - $photo_jpg = $vcard_obj->photo; - $tempfile = $tmpdir . '/' . basename($photo).".xml"; - echo PHP_EOL.$message_info."Saving image as XML: ".$tempfile; - file_put_contents($tempfile, $photo_jpg[0]['Value']); - - // convert base64 representation to jpg and delete tempfile afterwards - $this->base64_to_jpeg($tempfile, $photo.".jpg"); - unlink($tempfile); - - // copy photos via ftp to the FRITZ!Box - $file = $photo.".jpg"; - $remote_path = $this->config['usb_disk']."/FRITZ/fonpix"; - $remote_file = $photo.".jpg"; + foreach($this->config['carddav'] as $conf) { + $carddav = new carddav_backend($conf['url']); + $carddav->set_auth($conf['user'], $conf['pw']); + $xmldata = $carddav->get(); + + // convert everything to utf-8 (for OpenXchange/Appsuite) + //$xmldata = utf8_encode($xmldata); + + // DEBUG: writes an XML-file of the addressbook to the server from where the script is executed + /* + $filename = $conf['user']."_".basename($conf['url']) . ".xml"; + print PHP_EOL."Save whole addressbook as xml file: ".$filename; + file_put_contents($filename, $xmldata); + */ + + // read raw_vcard data from xml response + $raw_vcards = array(); + $xmlvcard = new SimpleXMLElement($xmldata); + + foreach($xmlvcard->element as $vcard_element) + { + $id = $vcard_element->id->__toString(); + $value = (string)$vcard_element->vcard->__toString(); + $raw_vcards[$id] = $value; + } + + // parse raw_vcards + $result = array(); + foreach($raw_vcards as $v) { + $vcard_obj = new vCard(false, $v); + + // name + $name_arr = $vcard_obj->n[0]; + $name = $this->_concat($this->_concat($name_arr['LastName'],$name_arr['FirstName']),$name_arr['AdditionalNames']); + + // if name is empty we take organization instead + if(empty($name)) { + $name_arr = $vcard_obj->org[0]; + $name = $name_arr['Name']; + } + + // format filename of contact photo; remove special letters + if ($vcard_obj->photo) { + $photo = str_replace(array(',','&',' ','/','ä','ö','ü','Ä','Ö','Ü','ß','á','à','ó','ò','ú','ù','í'), + array('','_','_','_','ae','oe','ue','Ae','Oe','Ue','ss','a','a','o','o','u','u','i'),$name); + } else { + $photo = ''; + } + + // phone + $phone_no = array(); + if ($vcard_obj->categories) { + $categories = $vcard_obj->categories[0]; + } else { + $categories = array(''); + } + + // e-mail addresses + $email_add = array(); + + // retrieve photos, save them as jpg and put them via ftp to the FRITZ!Box + if ($vcard_obj->photo) { + // get photos, rename and save as xml + $photo_jpg = $vcard_obj->photo; + $tempfile = $tmpdir . '/' . basename($photo).".xml"; + echo PHP_EOL.$message_info."Saving image as XML: ".$tempfile; + file_put_contents($tempfile, $photo_jpg[0]['Value']); + + // convert base64 representation to jpg and delete tempfile afterwards + $this->base64_to_jpeg($tempfile, $photo.".jpg"); + unlink($tempfile); + + // copy photos via ftp to the FRITZ!Box + $file = $photo.".jpg"; + $remote_path = $this->config['usb_disk']."/FRITZ/fonpix"; + $remote_file = $photo.".jpg"; // create remote path if it doesn't exist if (ftp_nlist($conn_id, $remote_path) == false) { ftp_mkdir($conn_id, $remote_path); } - // upload photo file. If successful delete afterwards - if (ftp_put($conn_id, $remote_path."/".$file, $remote_file, FTP_BINARY)) { - echo PHP_EOL.$message_successful."Successful upload of photo: ".$file; - unlink($file); - } else { - // retry when a fault occurs. - echo PHP_EOL.$message_error."While uploading file ".$file." an error occurred. - retrying".PHP_EOL; - $conn_id = ftp_ssl_connect($ftp_server); - $login_result = ftp_login($conn_id, $this->config['fritzbox_user'], $this->config['fritzbox_pw']); - ftp_pasv($conn_id, true); - if (ftp_put($conn_id, $remote_path."/".$file, $remote_file, FTP_BINARY)) { - echo PHP_EOL.$message_successful."Successful upload of photo: ".$file; - unlink($file); - } else { - echo PHP_EOL.$message_error."While uploading file ".$file." an error occurred. - giving up".PHP_EOL; - } - } - } - - if (in_array($this->config['group_vip'],$categories)) { - $vip = 1; - } else { - $vip = 0; - } - - if (array_key_exists('group_filter',$this->config)) { - $add_entry = 0; - foreach($this->config['group_filter'] as $group_filter) { - if (in_array($group_filter,$categories)) { - $add_entry = 1; - break; - } - } - } else { - $add_entry = 1; - } - - if ($add_entry == 1) { - foreach($vcard_obj->tel as $t) { - - $prio = 0; - if (!is_array($t) || empty($t['Type'])) { - $type = "mobile"; - $phone_number = $t; - } else { - $phone_number = $t['Value']; - - $typearr_lower = unserialize(strtolower(serialize($t['Type']))); - - // find out priority - if (in_array("pref", $typearr_lower)) { - $prio = 1; - } - - // set the proper type - if (in_array("work", $typearr_lower)) { - $type = "work"; - } - elseif (in_array("cell", $typearr_lower)) { - $type = "mobile"; - } - elseif (in_array("home", $typearr_lower)) { - $type = "home"; - } - elseif (in_array("fax", $typearr_lower)) { - $type = "fax_work"; - } - elseif (in_array("other", $typearr_lower)) { - $type = "other"; - } - elseif (in_array("dom", $typearr_lower)) { - $type = "other"; - } - else { - continue; - } - } - $phone_no[] = array("type"=>$type, "prio"=>$prio, "value" => $this->_clear_phone_number($phone_number)); - } - - // request email address and type - if ($vcard_obj->email){ - foreach($vcard_obj->email as $e) { - if (empty($e['Type'])) { - $type_email = "work"; - $email = $e; - } else { - $email = $e['Value']; - $typearr_lower = unserialize(strtolower(serialize($e['Type']))); - if (in_array("work", $typearr_lower)) { - $type_email = "work"; - } - elseif (in_array("home", $typearr_lower)) { - $type_email = "home"; - } - elseif (in_array("other", $typearr_lower)) { - $type_email = "other"; - } - else { - continue; - } - } - - // DEBUG: print out the email address on the console - //print $type_email.": ".$email."\n"; - - $email_add[] = array("type"=>$type_email, "value" => $email); - } - } - $entries[] = array("realName" => $name, "telephony" => $phone_no, "email" => $email_add, "vip" => $vip, "photo" => $photo); - } - } - } - - // close ftp connection - ftp_close($conn_id); + // upload photo file. If successful delete afterwards + if (ftp_put($conn_id, $remote_path."/".$file, $remote_file, FTP_BINARY)) { + echo PHP_EOL.$message_successful."Successful upload of photo: ".$file; + unlink($file); + } else { + // retry when a fault occurs. + echo PHP_EOL.$message_error."While uploading file ".$file." an error occurred. - retrying".PHP_EOL; + $conn_id = ftp_ssl_connect($ftp_server); + $login_result = ftp_login($conn_id, $this->config['fritzbox_user'], $this->config['fritzbox_pw']); + ftp_pasv($conn_id, true); + if (ftp_put($conn_id, $remote_path."/".$file, $remote_file, FTP_BINARY)) { + echo PHP_EOL.$message_successful."Successful upload of photo: ".$file; + unlink($file); + } else { + echo PHP_EOL.$message_error."While uploading file ".$file." an error occurred. - giving up".PHP_EOL; + } + } + } + + if (in_array($this->config['group_vip'],$categories)) { + $vip = 1; + } else { + $vip = 0; + } + + if (array_key_exists('group_filter',$this->config)) { + $add_entry = 0; + foreach($this->config['group_filter'] as $group_filter) { + if (in_array($group_filter,$categories)) { + $add_entry = 1; + break; + } + } + } else { + $add_entry = 1; + } + + if ($add_entry == 1) { + foreach($vcard_obj->tel as $t) { + + $prio = 0; + if (!is_array($t) || empty($t['Type'])) { + $type = "mobile"; + $phone_number = $t; + } else { + $phone_number = $t['Value']; + + $typearr_lower = unserialize(strtolower(serialize($t['Type']))); + + // find out priority + if (in_array("pref", $typearr_lower)) { + $prio = 1; + } + + // set the proper type + if (in_array("work", $typearr_lower)) { + $type = "work"; + } + elseif (in_array("cell", $typearr_lower)) { + $type = "mobile"; + } + elseif (in_array("home", $typearr_lower)) { + $type = "home"; + } + elseif (in_array("fax", $typearr_lower)) { + $type = "fax_work"; + } + elseif (in_array("other", $typearr_lower)) { + $type = "other"; + } + elseif (in_array("dom", $typearr_lower)) { + $type = "other"; + } + else { + continue; + } + } + $phone_no[] = array("type"=>$type, "prio"=>$prio, "value" => $this->_clear_phone_number($phone_number)); + } + + // request email address and type + if ($vcard_obj->email){ + foreach($vcard_obj->email as $e) { + if (empty($e['Type'])) { + $type_email = "work"; + $email = $e; + } else { + $email = $e['Value']; + $typearr_lower = unserialize(strtolower(serialize($e['Type']))); + if (in_array("work", $typearr_lower)) { + $type_email = "work"; + } + elseif (in_array("home", $typearr_lower)) { + $type_email = "home"; + } + elseif (in_array("other", $typearr_lower)) { + $type_email = "other"; + } + else { + continue; + } + } + + // DEBUG: print out the email address on the console + //print $type_email.": ".$email."\n"; + + $email_add[] = array("type"=>$type_email, "value" => $email); + } + } + $entries[] = array("realName" => $name, "telephony" => $phone_no, "email" => $email_add, "vip" => $vip, "photo" => $photo); + } + } + } + + // close ftp connection + ftp_close($conn_id); // remove temporary directory rmdir($tmpdir); - $this->entries = $entries; - } - - private function _clear_phone_number($number) { - return preg_replace("/[^0-9+]/", "", $number); - // return $number; - } - - public function build_fb_xml() { - - if(empty($this->entries)) { - throw new Exception('No entries available! Call get_carddav_entries or set $this->entries manually!'); - } - - // create FB XML in utf-8 format - $root = new SimpleXMLElement(''); - $pb = $root->phonebook; - $pb->addAttribute("name",$this->config['phonebook_name']); - - foreach($this->entries as $entry) { - - $contact = $pb->addChild("contact"); - $contact->addChild("category", $entry['vip']); - $person = $contact->addChild("person"); - $person->addChild("realName", $this->_convert_text($entry['realName'])); - - // contact photo: set path to contact photo on fritzbox - if (($entry['photo']) and (array_key_exists('usb_disk',$this->config))) { - $person->addChild("imageURL","file:///var/media/ftp/".$this->config['usb_disk']."/FRITZ/fonpix/".$entry['photo'].".jpg"); - } - - // telephone: put the phonenumbers into the fritzbox xml file - $telephony = $contact->addChild("telephony"); - $id = 0; - foreach($entry['telephony'] as $tel) { - $num = $telephony->addChild("number", $tel['value']); - $num->addAttribute("type", $tel['type']); - $num->addAttribute("vanity",""); - $num->addAttribute("prio", $tel['prio']); - $num->addAttribute("id", $id); - $id++; - } - - // email: put the email addresses into the fritzbox xml file - $email = $contact->addChild("services"); - $id = 0; - foreach($entry['email'] as $mail) { - $mail_adr = $email->addChild("email", $mail['value']); - $mail_adr->addAttribute("classifier", $mail['type']); - $mail_adr->addAttribute("id", $id); - $id++; - } - - $contact->addChild("services"); - $contact->addChild("setup"); - $contact->addChild("mod_time", (string)time()); - } - - $this->fbxml = $root->asXML(); - } - - public function _convert_text($text) { - $text = htmlspecialchars($text); - //$text = iconv("UTF-8", "ISO-8859-1//IGNORE", $text); - return $text; - } - - public function _concat ($text1,$text2) { - - if ($text1 == '') { - return $text2; - } - elseif ($text2 == '') { - return $text1; - } - else - { - return $text1.", ".$text2; - } - } - - public function _parse_fb_result($text) { - preg_match("/\([^\<]+)\<\/h2\>/", $text, $matches); - - if($matches) - return $matches[1]; - else - return "Error while uploading xml to fritzbox"; - } - - public function upload_to_fb() { - - if (array_key_exists('output_file',$this->config)) { - $output = fopen($this->config['output_file'], 'w'); - if ($output) { - fwrite($output, $this->fbxml); - fclose($output); - } - return 0; - }; - - $msg = ""; - - try - { - $fritz = new fritzbox_api($this->config['fritzbox_pw'],$this->config['fritzbox_user'],$this->config['fritzbox_ip']); - $formfields = array( - 'PhonebookId' => $this->config['phonebook_number'] - ); - - $filefileds = array('PhonebookImportFile' => array( - 'type' => 'text/xml', - 'filename' => 'updatepb.xml', - 'content' => $this->fbxml, - ) - ); - - $raw_result = $fritz->doPostFile($formfields, $filefileds); // send the command - $msg = $this->_parse_fb_result($raw_result); - $fritz = null; // destroy the object to log out - } - catch (Exception $e) - { - print $e->getMessage(); // show the error message in anything failed - print PHP_EOL; - } - return $msg; - } + $this->entries = $entries; + } + + private function _clear_phone_number($number) { + return preg_replace("/[^0-9+]/", "", $number); + // return $number; + } + + public function build_fb_xml() { + + if(empty($this->entries)) { + throw new Exception('No entries available! Call get_carddav_entries or set $this->entries manually!'); + } + + // create FB XML in utf-8 format + $root = new SimpleXMLElement(''); + $pb = $root->phonebook; + $pb->addAttribute("name",$this->config['phonebook_name']); + + foreach($this->entries as $entry) { + + $contact = $pb->addChild("contact"); + $contact->addChild("category", $entry['vip']); + $person = $contact->addChild("person"); + $person->addChild("realName", $this->_convert_text($entry['realName'])); + + // contact photo: set path to contact photo on fritzbox + if (($entry['photo']) and (array_key_exists('usb_disk',$this->config))) { + $person->addChild("imageURL","file:///var/media/ftp/".$this->config['usb_disk']."/FRITZ/fonpix/".$entry['photo'].".jpg"); + } + + // telephone: put the phonenumbers into the fritzbox xml file + $telephony = $contact->addChild("telephony"); + $id = 0; + foreach($entry['telephony'] as $tel) { + $num = $telephony->addChild("number", $tel['value']); + $num->addAttribute("type", $tel['type']); + $num->addAttribute("vanity",""); + $num->addAttribute("prio", $tel['prio']); + $num->addAttribute("id", $id); + $id++; + } + + // email: put the email addresses into the fritzbox xml file + $email = $contact->addChild("services"); + $id = 0; + foreach($entry['email'] as $mail) { + $mail_adr = $email->addChild("email", $mail['value']); + $mail_adr->addAttribute("classifier", $mail['type']); + $mail_adr->addAttribute("id", $id); + $id++; + } + + $contact->addChild("services"); + $contact->addChild("setup"); + $contact->addChild("mod_time", (string)time()); + } + + $this->fbxml = $root->asXML(); + } + + public function _convert_text($text) { + $text = htmlspecialchars($text); + //$text = iconv("UTF-8", "ISO-8859-1//IGNORE", $text); + return $text; + } + + public function _concat ($text1,$text2) { + + if ($text1 == '') { + return $text2; + } + elseif ($text2 == '') { + return $text1; + } + else + { + return $text1.", ".$text2; + } + } + + public function _parse_fb_result($text) { + preg_match("/\([^\<]+)\<\/h2\>/", $text, $matches); + + if($matches) + return $matches[1]; + else + return "Error while uploading xml to fritzbox"; + } + + public function upload_to_fb() { + + if (array_key_exists('output_file',$this->config)) { + $output = fopen($this->config['output_file'], 'w'); + if ($output) { + fwrite($output, $this->fbxml); + fclose($output); + } + return 0; + }; + + $msg = ""; + + try + { + $fritz = new fritzbox_api($this->config['fritzbox_pw'],$this->config['fritzbox_user'],$this->config['fritzbox_ip']); + $formfields = array( + 'PhonebookId' => $this->config['phonebook_number'] + ); + + $filefileds = array('PhonebookImportFile' => array( + 'type' => 'text/xml', + 'filename' => 'updatepb.xml', + 'content' => $this->fbxml, + ) + ); + + $raw_result = $fritz->doPostFile($formfields, $filefileds); // send the command + $msg = $this->_parse_fb_result($raw_result); + $fritz = null; // destroy the object to log out + } + catch (Exception $e) + { + print $e->getMessage(); // show the error message in anything failed + print PHP_EOL; + } + return $msg; + } } ?> diff --git a/config.example.php b/config.example.php index 64e78ecc..69f07ab0 100644 --- a/config.example.php +++ b/config.example.php @@ -34,15 +34,15 @@ // first $config['carddav'][0] = array( // URL of first CardDAV address book on cloud storage - 'url' => 'https://raspserver/owncloud/remote.php/carddav/addressbooks/fritzbox/fb_contacts', + 'url' => 'https://raspserver/owncloud/remote.php/carddav/addressbooks/fritzbox/fb_contacts', // user name/password for CardDAV access - 'user' => 'oc_username', - 'pw' => 'oc_password' + 'user' => 'oc_username', + 'pw' => 'oc_password' ); // second //$config['carddav'][1] = array( -// 'url' => 'https://raspserver/owncloud/remote.php/carddav/addressbooks/fritzbox/fb_contacts_second', -// 'user' => 'oc_username', -// 'pw' => 'oc_password' +// 'url' => 'https://raspserver/owncloud/remote.php/carddav/addressbooks/fritzbox/fb_contacts_second', +// 'user' => 'oc_username', +// 'pw' => 'oc_password' //);