baseDn = $baseDn; $this->searchScope = $searchScope; $this->filter = $filter; $this->attributes = $attributes; $this->includeSystem = $includeSystem; $this->saveAsFile = $saveAsFile; $this->format = $format; $this->ending = $ending; } /** * Starts the export process. * * @return string JSON result */ public function doExport() { try { $this->checkParameters(); $results = $this->getLDAPData(); return $this->writeDataAndReturnJson($results); } catch (LAMException $e) { $data = Exporter::formatMessage('ERROR', $e->getTitle(), $e->getMessage()); $status = array( Exporter::STATUS => 'failed', Exporter::DATA => $data ); return json_encode($status); } } /** * Returns the HTML for an error message. * * @param string $type message type (e.g. INFO) * @param string $title title * @param string $message message * @return string HTML */ public static function formatMessage($type, $title, $message) { $msg = new htmlStatusMessage($type, $title, $message); $tabindex = 0; ob_start(); $msg->generateHTML(null, array($msg), array(), true, $tabindex, 'user'); $data = ob_get_contents(); ob_clean(); return $data; } /** * Checks the input parameters for validity. * * @throws LAMException in case of errors */ private function checkParameters() { if (!get_preg($this->baseDn, 'dn')) { throw new LAMException(_('Please enter a valid DN in the field:'), _('Base DN')); } } /** * Returns the LDAP entries * * @return array[] LDAP entries */ private function getLDAPData() { $attributes = preg_split('/,[ ]*/', $this->attributes); if ($this->includeSystem) { $attributes = array_merge($attributes, array('+', 'passwordRetryCount', 'accountUnlockTime', 'nsAccountLock', 'nsRoleDN', 'passwordExpirationTime', 'pwdChangedTime')); } $attributes = array_unique($attributes); switch ($this->searchScope) { case 'base': return array(ldapGetDN($this->baseDn, $attributes)); break; case 'one': return ldapListDN($this->baseDn, $this->filter, $attributes); break; case 'sub': return searchLDAP($this->baseDn, $this->filter, $attributes); break; default: throw new LAMException('Invalid scope'); break; } } /** * Writes the entries to file/response and prints JSON. * * @param array $entries LDAP entries */ private function writeDataAndReturnJson(&$entries) { $lineEnding = ($this->ending === 'windows') ? "\r\n" : "\n"; if ($this->format === 'csv') { $output = $this->getCsvOutput($entries, $lineEnding); } elseif ($this->format === 'ldif') { $output = $this->getLdifOutput($entries, $lineEnding); } else { throw new LAMException('Invalid format'); } if ($this->saveAsFile) { $filename = '../../tmp/' . getRandomNumber() . time() .'.' . $this->format; $handle = fopen($filename, 'w'); chmod($filename, 0640); fwrite($handle, $output); fclose($handle); return json_encode(array( Exporter::FILE => $filename, Exporter::STATUS => 'done' )); } return json_encode(array( Exporter::OUTPUT => htmlspecialchars($output, ENT_NOQUOTES), Exporter::STATUS => 'done' )); } /** * Converts the given LDAP entries to CSV format. * * @param string $entries entries * @param string $lineEnding line ending */ private function getCsvOutput(&$entries, $lineEnding) { $attributeNames = array(); foreach ($entries as $entry) { $entryAttributeNames = array_keys($entry); foreach ($entryAttributeNames as $name) { if (!in_array($name, $attributeNames)) { $attributeNames[] = $name; } } } $attributeNames = array_delete(array('dn'), $attributeNames); sort($attributeNames); array_unshift($attributeNames, 'dn'); $attributeNamesQuoted = array_map(array($this, 'escapeCsvAndAddQuotes'), $attributeNames); $output = ''; // header $output .= implode(',', $attributeNamesQuoted) . $lineEnding; // content foreach ($entries as $entry) { $values = array(); foreach ($attributeNames as $name) { if (!isset($entry[$name])) { $values[] = $this->escapeCsvAndAddQuotes(''); } elseif (is_array($entry[$name])) { $values[] = $this->escapeCsvAndAddQuotes(implode(' | ', $entry[$name])); } else { $values[] = $this->escapeCsvAndAddQuotes($entry[$name]); } } $output .= implode(',', $values) . $lineEnding; } return $output; } /** * Escapes a CSV value and adds quotes around it. * * @param string $value CSV value * @return string escaped and quoted value */ private function escapeCsvAndAddQuotes($value) { return '"' . str_replace('"', '""', $value) . '"'; } /** * Converts the given LDAP entries to LDIF format. * * @param string $entries entries * @param string $lineEnding line ending */ private function getLdifOutput(&$entries, $lineEnding) { $output = ''; $output .= '#' . $lineEnding; $output .= '# ' . _('Base DN') . ': ' . $this->baseDn . $lineEnding; $output .= '# ' . _('Search scope') . ': ' . $this->searchScope . $lineEnding; $output .= '# ' . _('Search filter') . ': ' . $this->filter . $lineEnding; $output .= '# ' . _('Total entries') . ': ' . sizeof($entries) . $lineEnding; $output .= '#' . $lineEnding; $output .= '# Generated by LDAP Account Manager on ' . date('Y-m-d H:i:s') . $lineEnding; $output .= $lineEnding; $output .= $lineEnding; $output .= 'version: 1'; $output .= $lineEnding; $output .= $lineEnding; foreach ($entries as $entry) { $output .= 'dn: ' . $entry['dn'] . $lineEnding; unset($entry['dn']); ksort($entry); foreach ($entry as $attributeName => $values) { foreach ($values as $value) { if ($this->isPlainAscii($value)) { $output .= $this->wrapLdif($attributeName . ': ' . $value, $lineEnding) . $lineEnding; } else { $output .= $this->wrapLdif($attributeName . ':: ' . base64_encode($value), $lineEnding) . $lineEnding; } } } $output .= $lineEnding; } return $output; } /** * Splits the LDIF line if needed. * * @param string $content line content * @param string $lineEnding line ending */ private function wrapLdif($content, $lineEnding) { $line_length = 76; if (strlen($content) <= $line_length) { return $content; } $wrappedContent = substr($content, 0, $line_length) . $lineEnding; $contentLeft = substr($content, $line_length); $line_length = $line_length - 1; $lines = str_split($contentLeft, $line_length); foreach ($lines as $line) { $wrappedContent .= ' ' . $line . $lineEnding; } return trim($wrappedContent); } /** * Checks if the value is plain ASCII. * * @param string $content content to check * @return bool is plain ASCII */ private function isPlainAscii($content) { for ($i=0; $i < strlen($content); $i++) { if (ord($content[$i]) < 32 || ord($content[$i]) > 127) { return false; } } return true; } }