'ldif', 'desc' => 'LDIF', 'extension' => 'ldif' ); $exporters[] = array( 'output_type'=>'dsml', 'desc' => 'DSML V.1', 'extension' => 'xml' ); $exporters[] = array( 'output_type'=>'vcard', 'desc' => 'VCARD 2.1', 'extension' => 'vcf' ); $exporters[] = array( 'output_type'=>'csv', 'desc' => $lang['csv_spreadsheet'], 'extension' => 'csv' ); /** * This class encapsulate informations about the ldap server * from which the export is done. * The following info are provided within this class: * * $server_id: the id of the server. * $base_dn: if the source of the export is the ldap server, * it indicates the base dn of the search. * $query_filter: if the source of the export is the ldap server, * it indicates the query filter for the search. * $scope: if the source of the export is the ldap server, * it indicates the scope of the search. * * @package phpLDAPadmin */ class LdapExportInfo extends LDAPServer{ var $base_dn; var $query_filter; var $scope; /** * Create a new LdapExportInfo object * * @param int $server_id the server id * @param String $base_dn the base_dn for the search in a ldap server * @param String $query_filter the query filter for the search * @param String $scope the scope of the search in a ldap server */ function LdapExportInfo($server_id,$base_dn = NULL,$query_filter = NULL,$scope = NULL){ // Call our parent to initialise. parent::LDAPServer($server_id); // global $servers; $this->base_dn = $base_dn; $this->query_filter = $query_filter; $this->scope = $scope; } } /** * This class represents the base class of all exporters * It can be subclassed directly if your intend is to write * a source exporter(ie. it will act only as a decoree * which will be wrapped by an another exporter.) * If you consider writting an exporter for filtering data * or directly display entries, please consider subclass * the PlaExporter * * @see PlaExporter * @package phpLDAPadmin */ class PlaAbstractExporter{ /** * Return the number of entries * @return int the number of entries to be exported */ function pla_num_entries(){} /** * Return true if there is some more entries to be processed * @return bool if there is some more entries to be processed */ function pla_has_entry(){} /** * Return the entry as an array * @return array an entry as an array */ function pla_fetch_entry_array(){} /** * Return the entry as an Entry object * @return Entry an entry as an Entry Object */ function pla_fetch_entry_object(){} /** * Return a PlaLdapInfo Object * @return LdapInfo Object with info from the ldap serveur */ function pla_get_ldap_info(){} /** * May be call when the processing is finished * and to free some ressources. * @return bool true or false if any errors is encountered */ function pla_close(){} }// end PlaAbstractExporter /** * PlaExporter acts a wrapper around another exporter. * In other words, it will act as a decorator for another decorator * * @package phpLDAPadmin */ class PlaExporter extends PlaAbstractExporter{ // the default CRLN var $br="\n"; // the wrapped $exporter var $exporter; /** * Constructor * @param source $source the decoree for this exporter */ function PlaExporter( $source ){ $this->exporter = $source; } /** * Return the number of entries * @return int the number of entries to be exported */ function pla_num_entries(){ return $this->exporter->pla_num_entries(); } /** * Return true if there is some more entries to be processed * @return bool if there is some more entries to be processed */ function pla_has_entry(){ return $this->exporter->pla_has_entry(); } /** * Return the entry as an array * @return array an entry as an array */ function pla_fetch_entry_array(){ return $this->exporter->pla_fetch_entry_array(); } /** * Return the entry as an Entry object * @return Entry an entry as an Entry Object */ function pla_fetch_entry_object(){ return $this->exporter->pla_fetch_entry_object(); } /** * Return a PlaLdapInfo Object * @return LdapInfo Object with info from the ldap serveur */ function pla_get_ldap_info(){ return $this->exporter->pla_get_ldap_info(); } /** * May be call when the processing is finished * and to free some ressources. * @return bool false if any errors are encountered,false otherwise */ function pla_close(){ return $this->exporter->pla_close(); } /** * Helper method to check if the attribute value should be base 64 encoded. * @param String $str the string to check. * @return bool true if the string is safe ascii, false otherwise. */ function is_safe_ascii( $str ){ for( $i=0; $i 127 ) return false; return true; } /** * Abstract method use to export data. * Must be implemented in a sub-class if you write an exporter * which export data. * Leave it empty if you write a sub-class which do only some filtering. */ function export(){} /** * Set the carriage return /linefeed for the export * @param String $br the CRLF to be set */ function setOutputFormat( $br ){ $this->br = $br; } }// end PlaExporter /** * Export data from a ldap server * @extends PlaAbstractExporter * @package phpLDAPadmin */ class PlaLdapExporter extends PlaAbstractExporter{ var $entry_id; var $results; var $server_id; var $scope; var $entry_array; var $num_entries; var $ldap_info; var $queryFilter; var $hasNext; var $attributes; /** * Create a PlaLdapExporter object. * @param int $server_id the server id * @param String $queryFilter the queryFilter for the export * @param String $base_dn the base_dn for the data to export * @param String $scope the scope for export */ function PlaLdapExporter( $server_id , $queryFilter , $base_dn , $scope, $attributes){ global $lang; $this->scope = $scope; $this->base_dn = $base_dn; $this->server_id = $server_id; $this->queryFilter = $queryFilter; // infos for the server $this->ldap_info = new LdapExportInfo($server_id,$base_dn,$queryFilter,$scope); // boolean to check if there is more entries $this->hasNext = 0; // boolean to check the state of the connection $this->attributes = $attributes; // connect to the server $this->ds = $this->ldap_info->connect(); // @todo test whether we need to call pla_ldap_connection_is_error here. //pla_ldap_connection_is_error( $this->ds ); // get the data to be exported if( $this->scope == 'base' ) $this->results = @ldap_read( $this->ds, $this->base_dn, $this->queryFilter,$this->attributes, 0, 0, 0, get_export_deref_setting() ); elseif( $this->scope == 'one' ) $this->results = @ldap_list( $this->ds, $this->base_dn, $this->queryFilter, $this->attributes, 0, 0, 0, get_export_deref_setting() ); else // scope == 'sub' $this->results = @ldap_search( $this->ds, $this->base_dn, $this->queryFilter, $this->attributes, 0, 0, 0, get_export_deref_setting() ); // if no result, there is a something wrong if( ! $this->results ) pla_error( $lang['error_performing_search'], ldap_error( $this->ds ), ldap_errno( $this->ds ) ); // get the number of entries to be exported $this->num_entries = @ldap_count_entries( $this->ds,$this->results ); if( $this->entry_id = @ldap_first_entry( $this->ds,$this->results ) ){ $this->hasNext = 1; } }//end constructor /** * Return the entry as an array * @return array an entry as an array */ function pla_fetch_entry_array(){ return $this->entry_array; } /** * Return the entry as an Entry object * @return Entry an entry as an Entry Object */ function pla_fetch_entry_object(){ // to do } /** * Return a PlaLdapInfo Object * @return LdapInfo Object with info from the ldap serveur */ function pla_get_ldap_info(){ return $this->ldap_info; } /** * Return the number of entries * @return int the number of entries to be exported */ function pla_num_entries(){ return $this->num_entries; } /** * Return true if there is some more entries to be processed * @return bool if there is some more entries to be processed */ function pla_has_entry(){ if( $this->hasNext ){ unset( $this->entry_array ); $dn = @ldap_get_dn( $this->ds,$this->entry_id ); $this->entry_array['dn'] = $dn; //get the attributes of the entry $attrs = @ldap_get_attributes($this->ds,$this->entry_id); if( $attr = @ldap_first_attribute( $this->ds,$this->entry_id,$attrs ) ){ //iterate over the attributes while( $attr ){ if( is_attr_binary( $this,$attr ) ){ $this->entry_array[$attr] = @ldap_get_values_len( $this->ds,$this->entry_id,$attr ); } else{ $this->entry_array[$attr] = @ldap_get_values( $this->ds,$this->entry_id,$attr ); } unset( $this->entry_array[$attr]['count'] ); $attr = @ldap_next_attribute( $this->ds,$this->entry_id,$attrs ); }// end while attr if(!$this->entry_id = @ldap_next_entry( $this->ds,$this->entry_id ) ){ $this->hasNext = 0; } }// end if attr return true; } else{ $this->pla_close(); return false; } } /** * May be call when the processing is finished * and to free some ressources. * @return bool true or false if any errors is encountered * @todo This could break something, so need to add a method to LDAPServer to close connection and reset $connected. */ function pla_close(){ // if($this->ldap_info->connected){ // return @ldap_close( $this->ds ); // } // else{ // return true; // } } } // end PlaLdapExporter /** * Export entries to ldif format * @extends PlaExporter * @package phpLDAPadmin */ class PlaLdifExporter extends PlaExporter{ // variable to keep the count of the entries var $counter = 0; // the maximum length of the ldif line var $MAX_LDIF_LINE_LENGTH = 76; /** * Create a PlaLdifExporter object * @param PlaAbstractExporter $exporter the source exporter */ function PlaLdifExporter( $exporter ){ $this->exporter = $exporter; } /** * Export entries to ldif format */ function export(){ $pla_ldap_info = $this->pla_get_ldap_info(); $this->displayExportInfo($pla_ldap_info); //While there is an entry, fecth the entry as an array while($this->pla_has_entry()){ $entry = $this->pla_fetch_entry_array(); $this->counter++; // display comment before each entry global $lang; $title_string = "# " . $lang['entry'] . " " . $this->counter . ": " . $entry['dn'] ; if( strlen( $title_string ) > $this->MAX_LDIF_LINE_LENGTH-3 ) $title_string = substr( $title_string, 0, $this->MAX_LDIF_LINE_LENGTH-3 ) . "..."; echo "$title_string$this->br"; // display dn if( $this->is_safe_ascii( $entry['dn'] )) $this->multi_lines_display("dn: ". $entry['dn']); else $this->multi_lines_display("dn:: " . base64_encode( $entry['dn'] )); array_shift($entry); // display the attributes foreach( $entry as $key => $attr ){ foreach( $attr as $value ){ if( !$this->is_safe_ascii($value) || is_attr_binary($pla_ldap_info,$key ) ){ $this->multi_lines_display( $key.":: " . base64_encode( $value ) ); } else{ $this->multi_lines_display( $key.": ".$value ); } } }// end foreach $entry echo $this->br; // flush every 5th entry (sppeds things up a bit) if( 0 == $this->counter % 5 ) flush(); } } // display info related to this export function displayExportInfo($pla_ldap_info){ global $lang; echo "version: 1$this->br$this->br"; echo "# " . sprintf( $lang['ldif_export_for_dn'], $pla_ldap_info->base_dn ) . $this->br; echo "# " . sprintf( $lang['generated_on_date'], date("F j, Y g:i a") ) . $this->br; echo "# " . $lang['server'] . ": " .$pla_ldap_info->name . " (" . $pla_ldap_info->host . ")" . $this->br; echo "# " . $lang['search_scope'] . ": " . $pla_ldap_info->scope . $this->br; echo "# " . $lang['search_filter'] . ": " . $pla_ldap_info->query_filter . $this->br; echo "# " . $lang['total_entries'] . ": " . $this->pla_num_entries() . $this->br; echo $this->br; } /** * Helper method to wrap ldif lines * @param String $str the line to be wrapped if needed. */ function multi_lines_display( $str ){ $length_string = strlen($str); $max_length = $this->MAX_LDIF_LINE_LENGTH; while ($length_string > $max_length){ echo substr($str,0,$max_length).$this->br." "; $str= substr($str,$max_length,$length_string); $length_string = strlen($str); // need to do minus one to align on the right // the first line with the possible following lines // as these will have an extra space $max_length = $this->MAX_LDIF_LINE_LENGTH-1; } echo $str."".$this->br; } } /** * Export entries to DSML v.1 * @extends PlaExporter * @package phpLDAPadmin */ class PlaDsmlExporter extends PlaExporter{ //not in use var $indent_step = 2; var $counter = 0; /** * Create a PlaDsmlExporter object * @param PlaAbstractExporter $exporter the decoree exporter */ function PlaDsmlExporter( $exporter ){ $this->exporter = $exporter; } /** * Export the entries to DSML */ function export(){ global $lang; $pla_ldap_info = $this->pla_get_ldap_info(); // not very elegant, but do the job for the moment as we have just 4 level $directory_entries_indent = " "; $entry_indent= " "; $attr_indent = " "; $attr_value_indent = " "; // print declaration echo "$this->br"; // print root element echo "$this->br"; // print info related to this export echo "" . $this->br; echo $directory_entries_indent."$this->br"; //While there is an entry, fetch the entry as an array while($this->pla_has_entry()){ $entry = $this->pla_fetch_entry_array(); $this->counter++; // display dn echo $entry_indent."".$this->br; array_shift($entry); // echo the objectclass attributes first if(isset($entry['objectClass'])){ echo $attr_indent."".$this->br; foreach($entry['objectClass'] as $ocValue){ echo $attr_value_indent."$ocValue".$this->br; } echo $attr_indent."".$this->br; unset($entry['objectClass']); } $binary_mode = 0; // display the attributes foreach($entry as $key=>$attr){ echo $attr_indent."".$this->br; // if the attribute is binary, set the flag $binary_mode to true $binary_mode = is_attr_binary($pla_ldap_info,$key)?1:0; foreach($attr as $value){ echo $attr_value_indent."".($binary_mode?base64_encode( $value): htmlspecialchars( $value ) )."".$this->br; } echo $attr_indent."".$this->br; }// end foreach $entry echo $entry_indent."".$this->br; // flush every 5th entry (speeds things up a bit) if( 0 == $this->counter % 5 ) flush(); } echo $directory_entries_indent."$this->br"; echo "".$this->br; } } /** * @package phpLDAPadmin */ class PlaVcardExporter extends PlaExporter{ // mappping one to one attribute var $vcardMapping = array('cn' => 'FN', 'title' => 'TITLE', 'homePhone' => 'TEL;HOME', 'mobile' => 'TEL;CELL', 'mail' => 'EMAIL;Internet', 'labeledURI' =>'URL', 'o' => 'ORG', 'audio' => 'SOUND', 'facsmileTelephoneNumber' =>'TEL;WORK;HOME;VOICE;FAX', 'jpegPhoto' => 'PHOTO;ENCODING=BASE64', 'businessCategory' => 'ROLE', 'description' => 'NOTE' ); var $deliveryAddress = array("postOfficeBox", "street", "l", "st", "postalCode", "c"); function PlaVcardExporter($exporter){ $this->exporter = $exporter; } /** * When doing an exporter, the method export need to be overriden. * A basic implementation is provided here. Customize to your need **/ function export(){ // With the method pla->get_ldap_info, // you have access to some values related // to you ldap server $ldap_info = $this->pla_get_ldap_info(); $base_dn = $ldap_info->base_dn; $server_id = $ldap_info->server_id; $scope = $ldap_info->scope; $server_name = $ldap_info->name; $server_host = $ldap_info->host; while( $this->pla_has_entry() ){ $entry = $this->pla_fetch_entry_array(); //fetch the dn $dn = $entry['dn']; unset( $entry['dn'] ); // check the attributes needed for the delivery address // field $addr = "ADR:"; foreach( $this->deliveryAddress as $attr_name ){ if( isset( $entry[$attr_name] ) ){ $addr .= $entry[$attr_name][0]; unset($entry[$attr_name]); } $addr .= ';'; } echo "BEGIN:VCARD$this->br"; // loop for the attributes foreach( $entry as $attr_name=>$attr_values ){ // if an attribute of the ldap entry exist // in the mapping array for vcard if( isset( $this->vcardMapping[$attr_name] ) ){ // case of organisation. Need to append the // possible ou attribute if( 0 == strcasecmp( $attr_name , 'o' )){ echo $this->vcardMapping[$attr_name].":$attr_values[0]"; if( isset($entry['ou'] ) ) foreach( $entry['ou'] as $ou_value ){ echo ";$ou_value"; } } // the attribute is binary. (to do : need to fold the line) else if( 0 == strcasecmp( $attr_name,'audio') || 0 == strcasecmp( $attr_name,'jpegPhoto') ){ echo $this->vcardMapping[$attr_name].":$this->br"; echo " ".base64_encode( $attr_values[0]); } /* else if( $attr_name == "sn"){ echo $this->vcardMapping[$attr_name].":$attr_values[0]"; } elseif( $attr_name == "homePostalAddress"){ }*/ // else just print the value with the relevant attribute name else{ echo $this->vcardMapping[$attr_name].":$attr_values[0]"; } echo $this->br; } } // need to check echo "UID:$dn"; echo $this->br; echo "VERSION:2.1"; echo $this->br; echo $addr; echo $this->br; echo "END:VCARD"; echo $this->br; }// end while } } /** * Export to cvs format * * @author Glen Ogilvie * @package phpLDAPadmin */ class PlaCSVExporter extends PlaExporter{ function PlaCSVExporter($exporter){ $this->exporter = $exporter; } /** * When doing an exporter, the method export need to be overriden. * A basic implementation is provided here. Customize to your need **/ var $separator = ","; var $qualifier = '"'; var $multivalue_separator = " | "; var $escapeCode = '"'; function export(){ // With the method pla->get_ldap_info, // you have access to some values related // to you ldap server $ldap_info = $this->pla_get_ldap_info(); $base_dn = $ldap_info->base_dn; $server_id = $ldap_info->server_id; $scope = $ldap_info->scope; $server_name = $ldap_info->name; $server_host = $ldap_info->host; $entries = array(); $headers = array(); // go thru and find all the attribute names first. This is needed, because, otherwise we have // no idea as to which search attributes were actually populated with data while( $this->pla_has_entry() ) { $entry = $this->pla_fetch_entry_array(); foreach (array_keys($entry) as $key) { if (!in_array($key, $headers)) array_push($headers,$key); } array_push($entries, $entry); } $num_headers = count($headers); // print out the headers for ($i = 0; $i < $num_headers; $i++) { echo $this->qualifier. $headers[$i].$this->qualifier; if ($i < $num_headers-1) echo $this->separator; } array_shift($headers); $num_headers--; echo $this->br; // loop on every entry foreach ($entries as $entry) { //print the dn $dn = $entry['dn']; unset( $entry['dn'] ); echo $this->qualifier. $this->LdapEscape($dn).$this->qualifier.$this->separator; // print the attributes for($j=0;$j<$num_headers;$j++){ $attr_name = $headers[$j]; echo $this->qualifier; if (key_exists($attr_name, $entry)) { $binary_attribute = is_attr_binary( $ldap_info, $attr_name )?1:0; $attr_values = $entry[$attr_name]; $num_attr_values = count( $attr_values ); for( $i=0 ; $i<$num_attr_values; $i++){ if($binary_attribute) echo base64_encode($attr_values[$i]); else echo $this->LdapEscape($attr_values[$i]); if($i < $num_attr_values - 1) echo $this->multivalue_separator; } }// end if key echo $this->qualifier; if( $j < $num_headers - 1 ) echo $this->separator; } echo $this->br; } }//end export // function to escape data, where the qualifier happens to also // be in the data. function LdapEscape ($var) { return str_replace($this->qualifier, $this->escapeCode.$this->qualifier, $var); } } /** * @package phpLDAPadmin */ class MyCustomExporter extends PlaExporter{ function MyCutsomExporter($exporter){ $this->exporter = $exporter; } /** * When doing an exporter, the method export need to be overriden. * A basic implementation is provided here. Customize to your need **/ function export(){ // With the method pla->get_ldap_info, // you have access to some values related // to you ldap server $ldap_info = $this->pla_get_ldap_info(); $base_dn = $ldap_info->base_dn; $server_id = $ldap_info->server_id; $scope = $ldap_info->scope; $server_name = $ldap_info->name; $server_host = $ldap_info->host; // Just a simple loop. For each entry // do your custom export // see PlaLdifExporter or PlaDsmlExporter as an example while( $this->pla_has_entry() ){ $entry = $this->pla_fetch_entry_array(); //fetch the dn $dn = $entry['dn']; unset( $entry['dn'] ); // loop for the attributes foreach( $entry as $attr_name=>$attr_values ){ foreach( $attr_values as $value ){ // simple example // echo "Attribute Name:".$attr_name; // echo " - value:".$value; // echo $this->br; } } }// end while } } ?>