13 changed files with 2926 additions and 0 deletions
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
# Use image which contains apache with php |
||||
FROM php:7.4.13-apache |
||||
RUN echo "ServerName vcfconvert.yourdomain.com" >> /etc/apache2/apache2.conf |
||||
RUN apt-get update && apt-get upgrade -y |
||||
# Install packages needed to install php extensions |
||||
RUN apt-get install git zlib1g-dev libxml2-dev libzip-dev zip unzip -y |
||||
# Install PHP extensions |
||||
RUN docker-php-ext-install zip intl mysqli pdo pdo_mysql opcache |
||||
# Install NPM |
||||
RUN apt-get install npm -y |
||||
# Upgrade npm to latest version |
||||
RUN npm install -g npm |
||||
# Install node manager - n |
||||
RUN npm install -g n |
||||
# Install latest stable node version |
||||
RUN n stable |
||||
# Install sass compiler |
||||
RUN npm install -g sass |
||||
# Install XDEBUG |
||||
RUN pecl install xdebug-2.9.8 && docker-php-ext-enable xdebug |
||||
RUN echo 'xdebug.remote_port=9000' >> /usr/local/etc/php/php.ini |
||||
RUN echo 'xdebug.remote_enable=1' >> /usr/local/etc/php/php.ini |
||||
RUN echo 'xdebug.remote_connect_back=1' >> /usr/local/etc/php/php.ini |
||||
# Install composer command |
||||
RUN curl -sS https://getcomposer.org/installer | php && mv composer.phar /usr/local/bin/composer |
||||
# Install symfony command |
||||
RUN curl -sS https://get.symfony.com/cli/installer | bash && mv /root/.symfony/bin/symfony /usr/local/bin/symfony |
||||
# Set umask to 0000 (newly created files will have 777 permissions) |
||||
RUN echo "umask 0000" >> /root/.bashrc |
||||
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
<VirtualHost *:80> |
||||
ServerName vcfconvert.yourdomain.com |
||||
ServerAdmin webmaster@localhost |
||||
DocumentRoot /var/www/html/ |
||||
DirectoryIndex /index.php |
||||
|
||||
<Directory /var/www/html/public> |
||||
AllowOverride None |
||||
Order Allow,Deny |
||||
Allow from All |
||||
|
||||
FallbackResource /index.php |
||||
</Directory> |
||||
|
||||
<Directory /var/www/html/public/bundles> |
||||
FallbackResource disabled |
||||
</Directory> |
||||
ErrorLog ${APACHE_LOG_DIR}/error.log |
||||
CustomLog ${APACHE_LOG_DIR}/access.log combined |
||||
</VirtualHost> |
||||
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
php_flag display_errors Off |
||||
php_flag log_errors On |
||||
php_value error_log errors.log |
||||
php_value upload_max_filesize 8M |
||||
php_value post_max_size 9M |
||||
php_value max_execution_time 600 |
||||
@ -0,0 +1,841 @@
@@ -0,0 +1,841 @@
|
||||
<?php |
||||
/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */ |
||||
// +----------------------------------------------------------------------+ |
||||
// | PHP version 4 | |
||||
// +----------------------------------------------------------------------+ |
||||
// | Copyright (c) 1997-2002 The PHP Group | |
||||
// +----------------------------------------------------------------------+ |
||||
// | This source file is subject to version 2.0 of the PHP license, | |
||||
// | that is bundled with this package in the file LICENSE, and is | |
||||
// | available at through the world-wide-web at | |
||||
// | http://www.php.net/license/2_02.txt. | |
||||
// | If you did not receive a copy of the PHP license and are unable to | |
||||
// | obtain it through the world-wide-web, please send a note to | |
||||
// | license@php.net so we can mail you a copy immediately. | |
||||
// +----------------------------------------------------------------------+ |
||||
// | Authors: Paul M. Jones <pmjones@php.net> | |
||||
// +----------------------------------------------------------------------+ |
||||
// |
||||
// $Id: Contact_Vcard_Parse.php,v 1.4 2005/05/28 15:40:17 pmjones Exp $ |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Parser for vCards. |
||||
* |
||||
* This class parses vCard 2.1 and 3.0 sources from file or text into a |
||||
* structured array. |
||||
* |
||||
* Usage: |
||||
* |
||||
* <code> |
||||
* // include this class file |
||||
* require_once 'Contact_Vcard_Parse.php'; |
||||
* |
||||
* // instantiate a parser object |
||||
* $parse = new Contact_Vcard_Parse(); |
||||
* |
||||
* // parse a vCard file and store the data |
||||
* // in $cardinfo |
||||
* $cardinfo = $parse->fromFile('sample.vcf'); |
||||
* |
||||
* // view the card info array |
||||
* echo '<pre>'; |
||||
* print_r($cardinfo); |
||||
* echo '</pre>'; |
||||
* </code> |
||||
* |
||||
* |
||||
* @author Paul M. Jones <pmjones@php.net> |
||||
* |
||||
* @package Contact_Vcard_Parse |
||||
* |
||||
* @version 1.31 |
||||
* |
||||
*/ |
||||
|
||||
class Contact_Vcard_Parse { |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Reads a file for parsing, then sends it to $this->fromText() |
||||
* and returns the results. |
||||
* |
||||
* @access public |
||||
* |
||||
* @param array $filename The filename to read for vCard information. |
||||
* |
||||
* @return array An array of of vCard information extracted from the |
||||
* file. |
||||
* |
||||
* @see Contact_Vcard_Parse::fromText() |
||||
* |
||||
* @see Contact_Vcard_Parse::_fromArray() |
||||
* |
||||
*/ |
||||
|
||||
function fromFile($filename, $decode_qp = true) |
||||
{ |
||||
$text = $this->fileGetContents($filename); |
||||
|
||||
if ($text === false) { |
||||
return false; |
||||
} else { |
||||
// dump to, and get return from, the fromText() method. |
||||
return $this->fromText($text, $decode_qp); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Reads the contents of a file. Included for users whose PHP < 4.3.0. |
||||
* |
||||
* @access public |
||||
* |
||||
* @param array $filename The filename to read for vCard information. |
||||
* |
||||
* @return string|bool The contents of the file if it exists and is |
||||
* readable, or boolean false if not. |
||||
* |
||||
* @see Contact_Vcard_Parse::fromFile() |
||||
* |
||||
*/ |
||||
|
||||
function fileGetContents($filename) |
||||
{ |
||||
if (file_exists($filename) && |
||||
is_readable($filename)) { |
||||
|
||||
$text = ''; |
||||
$len = filesize($filename); |
||||
|
||||
$fp = fopen($filename, 'r'); |
||||
while ($line = fread($fp, filesize($filename))) { |
||||
$text .= $line; |
||||
} |
||||
fclose($fp); |
||||
|
||||
return $text; |
||||
|
||||
} else { |
||||
|
||||
return false; |
||||
|
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Prepares a block of text for parsing, then sends it through and |
||||
* returns the results from $this->fromArray(). |
||||
* |
||||
* @access public |
||||
* |
||||
* @param array $text A block of text to read for vCard information. |
||||
* |
||||
* @return array An array of vCard information extracted from the |
||||
* source text. |
||||
* |
||||
* @see Contact_Vcard_Parse::_fromArray() |
||||
* |
||||
*/ |
||||
|
||||
function fromText($text, $decode_qp = true) |
||||
{ |
||||
// convert all kinds of line endings to Unix-standard and get |
||||
// rid of double blank lines. |
||||
$this->convertLineEndings($text); |
||||
|
||||
// unfold lines. concat two lines where line 1 ends in \n and |
||||
// line 2 starts with a whitespace character. only removes |
||||
// the first whitespace character, leaves others in place. |
||||
$fold_regex = '(\n)([ |\t])'; |
||||
$text = preg_replace("/$fold_regex/i", "", $text); |
||||
|
||||
// massage for Macintosh OS X Address Book (remove nulls that |
||||
// Address Book puts in for unicode chars) |
||||
$text = str_replace("\x00", '', $text); |
||||
|
||||
// convert the resulting text to an array of lines |
||||
$lines = explode("\n", $text); |
||||
|
||||
// parse the array of lines and return vCard info |
||||
return $this->_fromArray($lines, $decode_qp); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Converts line endings in text. |
||||
* |
||||
* Takes any text block and converts all line endings to UNIX |
||||
* standard. DOS line endings are \r\n, Mac are \r, and UNIX is \n. |
||||
* |
||||
* NOTE: Acts on the text block in-place; does not return a value. |
||||
* |
||||
* @access public |
||||
* |
||||
* @param string $text The string on which to convert line endings. |
||||
* |
||||
* @return void |
||||
* |
||||
*/ |
||||
|
||||
function convertLineEndings(&$text) |
||||
{ |
||||
// DOS |
||||
$text = str_replace("\r\n", "\n", $text); |
||||
|
||||
// Mac |
||||
$text = str_replace("\r", "\n", $text); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Splits a string into an array at semicolons. Honors backslash- |
||||
* escaped semicolons (i.e., splits at ';' not '\;'). |
||||
* |
||||
* @access public |
||||
* |
||||
* @param string $text The string to split into an array. |
||||
* |
||||
* @param bool $convertSingle If splitting the string results in a |
||||
* single array element, return a string instead of a one-element |
||||
* array. |
||||
* |
||||
* @return mixed An array of values, or a single string. |
||||
* |
||||
*/ |
||||
|
||||
function splitBySemi($text, $convertSingle = false) |
||||
{ |
||||
// we use these double-backs (\\) because they get get converted |
||||
// to single-backs (\) by preg_split. the quad-backs (\\\\) end |
||||
// up as as double-backs (\\), which is what preg_split requires |
||||
// to indicate a single backslash (\). what a mess. |
||||
$regex = '(?<!\\\\)(\;)'; |
||||
$tmp = preg_split("/$regex/i", $text); |
||||
|
||||
// if there is only one array-element and $convertSingle is |
||||
// true, then return only the value of that one array element |
||||
// (instead of returning the array). |
||||
if ($convertSingle && count($tmp) == 1) { |
||||
return $tmp[0]; |
||||
} else { |
||||
return $tmp; |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Splits a string into an array at commas. Honors backslash- |
||||
* escaped commas (i.e., splits at ',' not '\,'). |
||||
* |
||||
* @access public |
||||
* |
||||
* @param string $text The string to split into an array. |
||||
* |
||||
* @param bool $convertSingle If splitting the string results in a |
||||
* single array element, return a string instead of a one-element |
||||
* array. |
||||
* |
||||
* @return mixed An array of values, or a single string. |
||||
* |
||||
*/ |
||||
|
||||
function splitByComma($text, $convertSingle = false) |
||||
{ |
||||
// we use these double-backs (\\) because they get get converted |
||||
// to single-backs (\) by preg_split. the quad-backs (\\\\) end |
||||
// up as as double-backs (\\), which is what preg_split requires |
||||
// to indicate a single backslash (\). ye gods, how ugly. |
||||
$regex = '(?<!\\\\)(\,)'; |
||||
$tmp = preg_split("/$regex/i", $text); |
||||
|
||||
// if there is only one array-element and $convertSingle is |
||||
// true, then return only the value of that one array element |
||||
// (instead of returning the array). |
||||
if ($convertSingle && count($tmp) == 1) { |
||||
return $tmp[0]; |
||||
} else { |
||||
return $tmp; |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Used to make string human-readable after being a vCard value. |
||||
* |
||||
* Converts... |
||||
* \: => : |
||||
* \; => ; |
||||
* \, => , |
||||
* literal \n => newline |
||||
* |
||||
* @access public |
||||
* |
||||
* @param mixed $text The text to unescape. |
||||
* |
||||
* @return void |
||||
* |
||||
*/ |
||||
|
||||
function unescape(&$text) |
||||
{ |
||||
if (is_array($text)) { |
||||
foreach ($text as $key => $val) { |
||||
$this->unescape($val); |
||||
$text[$key] = $val; |
||||
} |
||||
} else { |
||||
$text = str_replace('\:', ':', $text); |
||||
$text = str_replace('\;', ';', $text); |
||||
$text = str_replace('\,', ',', $text); |
||||
$text = str_replace('\n', "\n", $text); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Emulated destructor. |
||||
* |
||||
* @access private |
||||
* @return boolean true |
||||
* |
||||
*/ |
||||
|
||||
function _Contact_Vcard_Parse() |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Parses an array of source lines and returns an array of vCards. |
||||
* Each element of the array is itself an array expressing the types, |
||||
* parameters, and values of each part of the vCard. Processes both |
||||
* 2.1 and 3.0 vCard sources. |
||||
* |
||||
* @access private |
||||
* |
||||
* @param array $source An array of lines to be read for vCard |
||||
* information. |
||||
* |
||||
* @return array An array of of vCard information extracted from the |
||||
* source array. |
||||
* |
||||
*/ |
||||
|
||||
function _fromArray($source, $decode_qp = true) |
||||
{ |
||||
// the info array will hold all resulting vCard information. |
||||
$info = array(); |
||||
|
||||
// tells us whether the source text indicates the beginning of a |
||||
// new vCard with a BEGIN:VCARD tag. |
||||
$begin = false; |
||||
|
||||
// holds information about the current vCard being read from the |
||||
// source text. |
||||
$card = array(); |
||||
|
||||
// loop through each line in the source array |
||||
foreach ($source as $line) { |
||||
|
||||
// if the line is blank, skip it. |
||||
if (trim($line) == '') { |
||||
continue; |
||||
} |
||||
|
||||
// find the first instance of ':' on the line. The part |
||||
// to the left of the colon is the type and parameters; |
||||
// the part to the right of the colon is the value data. |
||||
$pos = strpos($line, ':'); |
||||
|
||||
// if there is no colon, skip the line. |
||||
if ($pos === false) { |
||||
continue; |
||||
} |
||||
|
||||
// get the left and right portions |
||||
$left = trim(substr($line, 0, $pos)); |
||||
$right = trim(substr($line, $pos+1, strlen($line))); |
||||
|
||||
// have we started yet? |
||||
if (! $begin) { |
||||
|
||||
// nope. does this line indicate the beginning of |
||||
// a new vCard? |
||||
if (strtoupper($left) == 'BEGIN' && |
||||
strtoupper($right) == 'VCARD') { |
||||
|
||||
// tell the loop that we've begun a new card |
||||
$begin = true; |
||||
} |
||||
|
||||
// regardless, loop to the next line of source. if begin |
||||
// is still false, the next loop will check the line. if |
||||
// begin has now been set to true, the loop will start |
||||
// collecting card info. |
||||
continue; |
||||
|
||||
} else { |
||||
|
||||
// yep, we've started, but we don't know how far along |
||||
// we are in the card. is this the ending line of the |
||||
// current vCard? |
||||
if (strtoupper($left) == 'END' && |
||||
strtoupper($right) == 'VCARD') { |
||||
|
||||
// yep, we're done. keep the info from the current |
||||
// card... |
||||
$info[] = $card; |
||||
|
||||
// ...and reset to grab a new card if one exists in |
||||
// the source array. |
||||
$begin = false; |
||||
$card = array(); |
||||
|
||||
} else { |
||||
|
||||
// we're not on an ending line, so collect info from |
||||
// this line into the current card. split the |
||||
// left-portion of the line into a type-definition |
||||
// (the kind of information) and parameters for the |
||||
// type. |
||||
$typedef = $this->_getTypeDef($left); |
||||
$params = $this->_getParams($left); |
||||
|
||||
// if we are decoding quoted-printable, do so now. |
||||
// QUOTED-PRINTABLE is not allowed in version 3.0, |
||||
// but we don't check for versioning, so we do it |
||||
// regardless. ;-) |
||||
$this->_decode_qp($params, $right); |
||||
|
||||
// now get the value-data from the line, based on |
||||
// the typedef |
||||
switch ($typedef) { |
||||
|
||||
case 'N': |
||||
// structured name of the person |
||||
$value = $this->_parseN($right); |
||||
break; |
||||
|
||||
case 'ADR': |
||||
// structured address of the person |
||||
$value = $this->_parseADR($right); |
||||
break; |
||||
|
||||
case 'NICKNAME': |
||||
// nicknames |
||||
$value = $this->_parseNICKNAME($right); |
||||
break; |
||||
|
||||
case 'ORG': |
||||
// organizations the person belongs to |
||||
$value = $this->_parseORG($right); |
||||
break; |
||||
|
||||
case 'CATEGORIES': |
||||
// categories to which this card is assigned |
||||
$value = $this->_parseCATEGORIES($right); |
||||
break; |
||||
|
||||
case 'GEO': |
||||
// geographic coordinates |
||||
$value = $this->_parseGEO($right); |
||||
break; |
||||
|
||||
default: |
||||
// by default, just grab the plain value. keep |
||||
// as an array to make sure *all* values are |
||||
// arrays. for consistency. ;-) |
||||
$value = array(array($right)); |
||||
break; |
||||
} |
||||
|
||||
// add the type, parameters, and value to the |
||||
// current card array. note that we allow multiple |
||||
// instances of the same type, which might be dumb |
||||
// in some cases (e.g., N). |
||||
$card[$typedef][] = array( |
||||
'param' => $params, |
||||
'value' => $value |
||||
); |
||||
} |
||||
} |
||||
} |
||||
|
||||
$this->unescape($info); |
||||
return $info; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Takes a vCard line and extracts the Type-Definition for the line. |
||||
* |
||||
* @access private |
||||
* |
||||
* @param string $text A left-part (before-the-colon part) from a |
||||
* vCard line. |
||||
* |
||||
* @return string The type definition for the line. |
||||
* |
||||
*/ |
||||
|
||||
function _getTypeDef($text) |
||||
{ |
||||
// split the text by semicolons |
||||
$split = $this->splitBySemi($text); |
||||
|
||||
// only return first element (the typedef) |
||||
return strtoupper($split[0]); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Finds the Type-Definition parameters for a vCard line. |
||||
* |
||||
* @access private |
||||
* |
||||
* @param string $text A left-part (before-the-colon part) from a |
||||
* vCard line. |
||||
* |
||||
* @return mixed An array of parameters. |
||||
* |
||||
*/ |
||||
|
||||
function _getParams($text) |
||||
{ |
||||
// split the text by semicolons into an array |
||||
$split = $this->splitBySemi($text); |
||||
|
||||
// drop the first element of the array (the type-definition) |
||||
array_shift($split); |
||||
|
||||
// set up an array to retain the parameters, if any |
||||
$params = array(); |
||||
|
||||
// loop through each parameter. the params may be in the format... |
||||
// "TYPE=type1,type2,type3" |
||||
// ...or... |
||||
// "TYPE=type1;TYPE=type2;TYPE=type3" |
||||
foreach ($split as $full) { |
||||
|
||||
// split the full parameter at the equal sign so we can tell |
||||
// the parameter name from the parameter value |
||||
$tmp = explode("=", $full); |
||||
|
||||
// the key is the left portion of the parameter (before |
||||
// '='). if in 2.1 format, the key may in fact be the |
||||
// parameter value, not the parameter name. |
||||
$key = strtoupper(trim($tmp[0])); |
||||
|
||||
// get the parameter name by checking to see if it's in |
||||
// vCard 2.1 or 3.0 format. |
||||
$name = $this->_getParamName($key); |
||||
|
||||
// list of all parameter values |
||||
$listall = trim($tmp[1]); |
||||
|
||||
// if there is a value-list for this parameter, they are |
||||
// separated by commas, so split them out too. |
||||
$list = $this->splitByComma($listall); |
||||
|
||||
// now loop through each value in the parameter and retain |
||||
// it. if the value is blank, that means it's a 2.1-style |
||||
// param, and the key itself is the value. |
||||
foreach ($list as $val) { |
||||
if (trim($val) != '') { |
||||
// 3.0 formatted parameter |
||||
$params[$name][] = trim($val); |
||||
} else { |
||||
// 2.1 formatted parameter |
||||
$params[$name][] = $key; |
||||
} |
||||
} |
||||
|
||||
// if, after all this, there are no parameter values for the |
||||
// parameter name, retain no info about the parameter (saves |
||||
// ram and checking-time later). |
||||
if (count($params[$name]) == 0) { |
||||
unset($params[$name]); |
||||
} |
||||
} |
||||
|
||||
// return the parameters array. |
||||
return $params; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Looks at the parameters of a vCard line; if one of them is |
||||
* ENCODING[] => QUOTED-PRINTABLE then decode the text in-place. |
||||
* |
||||
* @access private |
||||
* |
||||
* @param array $params A parameter array from a vCard line. |
||||
* |
||||
* @param string $text A right-part (after-the-colon part) from a |
||||
* vCard line. |
||||
* |
||||
* @return void |
||||
* |
||||
*/ |
||||
|
||||
function _decode_qp(&$params, &$text) |
||||
{ |
||||
// loop through each parameter |
||||
foreach ($params as $param_key => $param_val) { |
||||
|
||||
// check to see if it's an encoding param |
||||
if (trim(strtoupper($param_key)) == 'ENCODING') { |
||||
|
||||
// loop through each encoding param value |
||||
foreach ($param_val as $enc_key => $enc_val) { |
||||
|
||||
// if any of the values are QP, decode the text |
||||
// in-place and return |
||||
if (trim(strtoupper($enc_val)) == 'QUOTED-PRINTABLE') { |
||||
$text = quoted_printable_decode($text); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Returns parameter names from 2.1-formatted vCards. |
||||
* |
||||
* The vCard 2.1 specification allows parameter values without a |
||||
* name. The parameter name is then determined from the unique |
||||
* parameter value. |
||||
* |
||||
* Shamelessly lifted from Frank Hellwig <frank@hellwig.org> and his |
||||
* vCard PHP project <http://vcardphp.sourceforge.net>. |
||||
* |
||||
* @access private |
||||
* |
||||
* @param string $value The first element in a parameter name-value |
||||
* pair. |
||||
* |
||||
* @return string The proper parameter name (TYPE, ENCODING, or |
||||
* VALUE). |
||||
* |
||||
*/ |
||||
|
||||
function _getParamName($value) |
||||
{ |
||||
static $types = array ( |
||||
'DOM', 'INTL', 'POSTAL', 'PARCEL','HOME', 'WORK', |
||||
'PREF', 'VOICE', 'FAX', 'MSG', 'CELL', 'PAGER', |
||||
'BBS', 'MODEM', 'CAR', 'ISDN', 'VIDEO', |
||||
'AOL', 'APPLELINK', 'ATTMAIL', 'CIS', 'EWORLD', |
||||
'INTERNET', 'IBMMAIL', 'MCIMAIL', |
||||
'POWERSHARE', 'PRODIGY', 'TLX', 'X400', |
||||
'GIF', 'CGM', 'WMF', 'BMP', 'MET', 'PMB', 'DIB', |
||||
'PICT', 'TIFF', 'PDF', 'PS', 'JPEG', 'QTIME', |
||||
'MPEG', 'MPEG2', 'AVI', |
||||
'WAVE', 'AIFF', 'PCM', |
||||
'X509', 'PGP' |
||||
); |
||||
|
||||
// CONTENT-ID added by pmj |
||||
static $values = array ( |
||||
'INLINE', 'URL', 'CID', 'CONTENT-ID' |
||||
); |
||||
|
||||
// 8BIT added by pmj |
||||
static $encodings = array ( |
||||
'7BIT', '8BIT', 'QUOTED-PRINTABLE', 'BASE64' |
||||
); |
||||
|
||||
// changed by pmj to the following so that the name defaults to |
||||
// whatever the original value was. Frank Hellwig's original |
||||
// code was "$name = 'UNKNOWN'". |
||||
$name = $value; |
||||
|
||||
if (in_array($value, $types)) { |
||||
$name = 'TYPE'; |
||||
} elseif (in_array($value, $values)) { |
||||
$name = 'VALUE'; |
||||
} elseif (in_array($value, $encodings)) { |
||||
$name = 'ENCODING'; |
||||
} |
||||
|
||||
return $name; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Parses a vCard line value identified as being of the "N" |
||||
* (structured name) type-defintion. |
||||
* |
||||
* @access private |
||||
* |
||||
* @param string $text The right-part (after-the-colon part) of a |
||||
* vCard line. |
||||
* |
||||
* @return array An array of key-value pairs where the key is the |
||||
* portion-name and the value is the portion-value. The value itself |
||||
* may be an array as well if multiple comma-separated values were |
||||
* indicated in the vCard source. |
||||
* |
||||
*/ |
||||
|
||||
function _parseN($text) |
||||
{ |
||||
// make sure there are always at least 5 elements |
||||
$tmp = array_pad($this->splitBySemi($text), 5, ''); |
||||
return array( |
||||
$this->splitByComma($tmp[0]), // family (last) |
||||
$this->splitByComma($tmp[1]), // given (first) |
||||
$this->splitByComma($tmp[2]), // addl (middle) |
||||
$this->splitByComma($tmp[3]), // prefix |
||||
$this->splitByComma($tmp[4]) // suffix |
||||
); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Parses a vCard line value identified as being of the "ADR" |
||||
* (structured address) type-defintion. |
||||
* |
||||
* @access private |
||||
* |
||||
* @param string $text The right-part (after-the-colon part) of a |
||||
* vCard line. |
||||
* |
||||
* @return array An array of key-value pairs where the key is the |
||||
* portion-name and the value is the portion-value. The value itself |
||||
* may be an array as well if multiple comma-separated values were |
||||
* indicated in the vCard source. |
||||
* |
||||
*/ |
||||
|
||||
function _parseADR($text) |
||||
{ |
||||
// make sure there are always at least 7 elements |
||||
$tmp = array_pad($this->splitBySemi($text), 7, ''); |
||||
return array( |
||||
$this->splitByComma($tmp[0]), // pob |
||||
$this->splitByComma($tmp[1]), // extend |
||||
$this->splitByComma($tmp[2]), // street |
||||
$this->splitByComma($tmp[3]), // locality (city) |
||||
$this->splitByComma($tmp[4]), // region (state) |
||||
$this->splitByComma($tmp[5]), // postcode (ZIP) |
||||
$this->splitByComma($tmp[6]) // country |
||||
); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Parses a vCard line value identified as being of the "NICKNAME" |
||||
* (informal or descriptive name) type-defintion. |
||||
* |
||||
* @access private |
||||
* |
||||
* @param string $text The right-part (after-the-colon part) of a |
||||
* vCard line. |
||||
* |
||||
* @return array An array of nicknames. |
||||
* |
||||
*/ |
||||
|
||||
function _parseNICKNAME($text) |
||||
{ |
||||
return array($this->splitByComma($text)); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Parses a vCard line value identified as being of the "ORG" |
||||
* (organizational info) type-defintion. |
||||
* |
||||
* @access private |
||||
* |
||||
* @param string $text The right-part (after-the-colon part) of a |
||||
* vCard line. |
||||
* |
||||
* @return array An array of organizations; each element of the array |
||||
* is itself an array, which indicates primary organization and |
||||
* sub-organizations. |
||||
* |
||||
*/ |
||||
|
||||
function _parseORG($text) |
||||
{ |
||||
$tmp = $this->splitbySemi($text); |
||||
$list = array(); |
||||
foreach ($tmp as $val) { |
||||
$list[] = array($val); |
||||
} |
||||
|
||||
return $list; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Parses a vCard line value identified as being of the "CATEGORIES" |
||||
* (card-category) type-defintion. |
||||
* |
||||
* @access private |
||||
* |
||||
* @param string $text The right-part (after-the-colon part) of a |
||||
* vCard line. |
||||
* |
||||
* @return mixed An array of categories. |
||||
* |
||||
*/ |
||||
|
||||
function _parseCATEGORIES($text) |
||||
{ |
||||
return array($this->splitByComma($text)); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* Parses a vCard line value identified as being of the "GEO" |
||||
* (geographic coordinate) type-defintion. |
||||
* |
||||
* @access private |
||||
* |
||||
* @param string $text The right-part (after-the-colon part) of a |
||||
* vCard line. |
||||
* |
||||
* @return mixed An array of lat-lon geocoords. |
||||
* |
||||
*/ |
||||
|
||||
function _parseGEO($text) |
||||
{ |
||||
// make sure there are always at least 2 elements |
||||
$tmp = array_pad($this->splitBySemi($text), 2, ''); |
||||
return array( |
||||
array($tmp[0]), // lat |
||||
array($tmp[1]) // lon |
||||
); |
||||
} |
||||
} |
||||
|
||||
?> |
||||
@ -0,0 +1,225 @@
@@ -0,0 +1,225 @@
|
||||
This one is for mainly my own reference that is why it isn't listed on the main README.md in this repository. |
||||
|
||||
For this project, I used the [symfony](https://github.com/kasteckis/symfony-docker-compose) docker container to host a php application, [vCard to LDIF/CSV Converter](https://github.com/thomascube/vcfconvert) by u/thomascube. |
||||
|
||||
Symfony can help you host any php application. For this example, I selfhost vcfconvert. |
||||
|
||||
### Minimum File Structure |
||||
``` |
||||
/home/ |
||||
└── ~/ |
||||
└── docker/ |
||||
└── vcfconvert/ |
||||
├── .docker <-- This is a directory |
||||
├── Dockerfile |
||||
├── virtualhost.conf |
||||
├── docker-compose.yml |
||||
├── <PHP APPLICATION FILES> |
||||
|
||||
``` |
||||
### Add to Caddyfile (from ~/docker/caddy) |
||||
Remember to `docker exec -w /etc/caddy caddy caddy reload` after editing your Caddyfile. |
||||
``` |
||||
vcfconvert.yourdomain.com { |
||||
reverse_proxy vcfconvert:80 |
||||
} |
||||
``` |
||||
|
||||
### .docker/Dockerfile |
||||
The only thing you need to change in this file is the second line `RUN echo "ServerName vcfconvert.yourdomain.com" >> /etc/apache2/apache2.conf` use your own domain here. |
||||
|
||||
``` |
||||
# Use image which contains apache with php |
||||
FROM php:7.4.13-apache |
||||
RUN echo "ServerName vcfconvert.yourdomain.com" >> /etc/apache2/apache2.conf |
||||
RUN apt-get update && apt-get upgrade -y |
||||
# Install packages needed to install php extensions |
||||
RUN apt-get install git zlib1g-dev libxml2-dev libzip-dev zip unzip -y |
||||
# Install PHP extensions |
||||
RUN docker-php-ext-install zip intl mysqli pdo pdo_mysql opcache |
||||
# Install NPM |
||||
RUN apt-get install npm -y |
||||
# Upgrade npm to latest version |
||||
RUN npm install -g npm |
||||
# Install node manager - n |
||||
RUN npm install -g n |
||||
# Install latest stable node version |
||||
RUN n stable |
||||
# Install sass compiler |
||||
RUN npm install -g sass |
||||
# Install XDEBUG |
||||
RUN pecl install xdebug-2.9.8 && docker-php-ext-enable xdebug |
||||
RUN echo 'xdebug.remote_port=9000' >> /usr/local/etc/php/php.ini |
||||
RUN echo 'xdebug.remote_enable=1' >> /usr/local/etc/php/php.ini |
||||
RUN echo 'xdebug.remote_connect_back=1' >> /usr/local/etc/php/php.ini |
||||
# Install composer command |
||||
RUN curl -sS https://getcomposer.org/installer | php && mv composer.phar /usr/local/bin/composer |
||||
# Install symfony command |
||||
RUN curl -sS https://get.symfony.com/cli/installer | bash && mv /root/.symfony/bin/symfony /usr/local/bin/symfony |
||||
# Set umask to 0000 (newly created files will have 777 permissions) |
||||
RUN echo "umask 0000" >> /root/.bashrc |
||||
``` |
||||
|
||||
### .docker/virtualhost.conf |
||||
Again change the second line to your own domain. `ServerName vcfconvert.yourdomain.com` |
||||
``` |
||||
<VirtualHost *:80> |
||||
ServerName vcfconvert.yourdomain.com |
||||
ServerAdmin webmaster@localhost |
||||
DocumentRoot /var/www/html/ |
||||
DirectoryIndex /index.php |
||||
|
||||
<Directory /var/www/html/public> |
||||
AllowOverride None |
||||
Order Allow,Deny |
||||
Allow from All |
||||
|
||||
FallbackResource /index.php |
||||
</Directory> |
||||
|
||||
<Directory /var/www/html/public/bundles> |
||||
FallbackResource disabled |
||||
</Directory> |
||||
ErrorLog ${APACHE_LOG_DIR}/error.log |
||||
CustomLog ${APACHE_LOG_DIR}/access.log combined |
||||
</VirtualHost> |
||||
|
||||
``` |
||||
|
||||
### docker-compose.yml |
||||
Here you want to focus on the `web:` section. |
||||
|
||||
Here I added the caddy network which is similar to all my previous self-hosted docker apps. This is so I can have caddy reverse proxy into the php app's container. |
||||
|
||||
For the volumes. I wrote in the path of the directory that contains the `index.php` file and point it to `/var/www/html/` in the container. |
||||
|
||||
``` |
||||
version: "3" |
||||
services: |
||||
mysql: |
||||
image: mysql:5.7 |
||||
container_name: project_mysql |
||||
restart: unless-stopped |
||||
networks: |
||||
default: |
||||
ipv4_address: 192.168.2.3 |
||||
environment: |
||||
MYSQL_ALLOW_EMPTY_PASSWORD: "true" |
||||
MYSQL_ROOT_PASSWORD: |
||||
MYSQL_DATABASE: project |
||||
MYSQL_USER: root |
||||
MYSQL_PASSWORD: |
||||
ports: |
||||
- "9906:3306" |
||||
phpmyadmin: |
||||
image: phpmyadmin/phpmyadmin |
||||
container_name: project_phpmyadmin |
||||
links: |
||||
- mysql |
||||
environment: |
||||
PMA_HOST: mysql |
||||
PMA_PORT: 3306 |
||||
PMA_ARBITRARY: 1 |
||||
networks: |
||||
default: |
||||
ipv4_address: 192.168.2.4 |
||||
ports: |
||||
- 81:80 |
||||
|
||||
web: |
||||
build: ./.docker |
||||
container_name: vcfconvert |
||||
networks: |
||||
default: |
||||
ipv4_address: 192.168.2.2 |
||||
caddy: |
||||
volumes: |
||||
- ./:/var/www/html/ |
||||
- ./.docker/virtualhost.conf:/etc/apache2/sites-available/000-default.conf |
||||
ports: |
||||
- "9080:80" |
||||
depends_on: |
||||
- "mysql" |
||||
|
||||
mailhog: |
||||
image: mailhog/mailhog |
||||
container_name: project_mailhog |
||||
ports: |
||||
- 1025:1025 # smtp server |
||||
- 8025:8025 # web ui |
||||
networks: |
||||
default: |
||||
ipv4_address: 192.168.2.5 |
||||
|
||||
networks: |
||||
default: |
||||
driver: bridge |
||||
ipam: |
||||
driver: default |
||||
config: |
||||
- subnet: 192.168.2.0/24 # If you change this, make sure to change other IP addresses |
||||
caddy: |
||||
external: |
||||
name: caddy_net |
||||
``` |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
vCard to LDIF/CSV Converter |
||||
=========================== |
||||
by Thomas Bruederli |
||||
|
||||
To run this converter just copy all files to a webserver directory where PHP |
||||
is installed and enabled. Open your browser and type in the URL of your |
||||
webserver with the according folder. By default, file uploads up to 2MB are |
||||
allowed. |
||||
|
||||
Command line version |
||||
-------------------- |
||||
This package also includes a shell script to invoke the converter from the |
||||
command line. PHP is also required to be installed on your machine. |
||||
Just copy the files anywhere on your disk, open a terminal and type the |
||||
following commands: |
||||
|
||||
$ cd /path/to/vcfconvert |
||||
$ ./vcfconvert.sh -f ldif -o destination_file.ldif source_file.vcf |
||||
or |
||||
|
||||
$ ./vcfconvert.sh -hv -f csv -d ";" -o destination_file.csv source_file.vcf |
||||
|
||||
To get information about optinal parameters, type |
||||
|
||||
$ ./vcfconvert.sh help |
||||
|
||||
LICENSE |
||||
------- |
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 2 of the License, |
||||
or (at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program. If not, see [www.gnu.org/licenses/][gpl2]. |
||||
|
||||
For any bug reports or feature requests please open issue tickets at |
||||
[github.com/thomascube/vcfconvert][github]. |
||||
|
||||
|
||||
#### Note from Kevin on libdlusb compatibility |
||||
Due to the fact libdlusb is incapable of transmitting all the information |
||||
generally used with the contact application (currently it is capable of |
||||
only transmitting name, type, and phone number) I have intentionally organized |
||||
the format to be convenient for saving into the note application instead. This |
||||
allows the user to have multiple phone numbers per entry along with an e-mail |
||||
address. |
||||
|
||||
[gpl2]: http://www.gnu.org/licenses/gpl2.txt |
||||
[github]: http://github.com/thomascube/vcfconvert |
||||
|
||||
@ -0,0 +1,67 @@
@@ -0,0 +1,67 @@
|
||||
version: "3" |
||||
services: |
||||
mysql: |
||||
image: mysql:5.7 |
||||
container_name: project_mysql |
||||
restart: unless-stopped |
||||
networks: |
||||
default: |
||||
ipv4_address: 192.168.2.3 |
||||
environment: |
||||
MYSQL_ALLOW_EMPTY_PASSWORD: "true" |
||||
MYSQL_ROOT_PASSWORD: |
||||
MYSQL_DATABASE: project |
||||
MYSQL_USER: root |
||||
MYSQL_PASSWORD: |
||||
ports: |
||||
- "9906:3306" |
||||
phpmyadmin: |
||||
image: phpmyadmin/phpmyadmin |
||||
container_name: project_phpmyadmin |
||||
links: |
||||
- mysql |
||||
environment: |
||||
PMA_HOST: mysql |
||||
PMA_PORT: 3306 |
||||
PMA_ARBITRARY: 1 |
||||
networks: |
||||
default: |
||||
ipv4_address: 192.168.2.4 |
||||
ports: |
||||
- 81:80 |
||||
|
||||
web: |
||||
build: ./.docker |
||||
container_name: vcfconvert |
||||
networks: |
||||
default: |
||||
ipv4_address: 192.168.2.2 |
||||
caddy: |
||||
volumes: |
||||
- ./:/var/www/html/ |
||||
- ./.docker/virtualhost.conf:/etc/apache2/sites-available/000-default.conf |
||||
ports: |
||||
- "9080:80" |
||||
depends_on: |
||||
- "mysql" |
||||
|
||||
mailhog: |
||||
image: mailhog/mailhog |
||||
container_name: project_mailhog |
||||
ports: |
||||
- 1025:1025 # smtp server |
||||
- 8025:8025 # web ui |
||||
networks: |
||||
default: |
||||
ipv4_address: 192.168.2.5 |
||||
|
||||
networks: |
||||
default: |
||||
driver: bridge |
||||
ipam: |
||||
driver: default |
||||
config: |
||||
- subnet: 192.168.2.0/24 # If you change this, make sure to change other IP addresses |
||||
caddy: |
||||
external: |
||||
name: caddy_net |
||||
@ -0,0 +1,138 @@
@@ -0,0 +1,138 @@
|
||||
<?php |
||||
|
||||
/* |
||||
+-----------------------------------------------------------------------+ |
||||
| vCard to LDIF/CSV Converter | |
||||
| Version 0.9.0 | |
||||
| | |
||||
| Copyright (C) 2006-2013, Thomas Bruederli - Switzerland | |
||||
| Licensed under the GNU GPL | |
||||
| | |
||||
| Redistribution and use in source and binary forms, with or without | |
||||
| modification, are permitted provided that the following conditions | |
||||
| are met: | |
||||
| | |
||||
| o Redistributions of source code must retain the above copyright | |
||||
| notice, this list of conditions and the following disclaimer. | |
||||
| o Redistributions in binary form must reproduce the above copyright | |
||||
| notice, this list of conditions and the following disclaimer in the | |
||||
| documentation and/or other materials provided with the distribution.| |
||||
| o The names of the authors may not be used to endorse or promote | |
||||
| products derived from this software without specific prior written | |
||||
| permission. | |
||||
| | |
||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
||||
| | |
||||
+-----------------------------------------------------------------------+ |
||||
| Author: Thomas Bruederli <thomas@brotherli.ch> | |
||||
+-----------------------------------------------------------------------+ |
||||
|
||||
*/ |
||||
|
||||
// suppress php notices |
||||
@ini_set('error_reporting', E_ALL&~E_NOTICE); |
||||
|
||||
// include the converter class file |
||||
require_once('vcard_convert.php'); |
||||
require_once('utils.php'); |
||||
|
||||
|
||||
if (!empty($_FILES['_vcards'])) |
||||
{ |
||||
// instantiate a parser object |
||||
$conv = new vcard_convert(array( |
||||
'mailonly' => !empty($_POST['_mailonly']), |
||||
'phoneonly' => !empty($_POST['_phoneonly']), |
||||
'accesscode' => preg_replace('/[^1-9]/', '', $_POST['_accesscode']), |
||||
)); |
||||
|
||||
// check for errors |
||||
if ($err = $_FILES['_vcards']['error']) |
||||
{ |
||||
$GLOBALS['error_msg'] = ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) ? |
||||
"The uploaded file was too big! Maximum file size allowed: ".show_bytes(parse_bytes(ini_get('upload_max_filesize'))) : |
||||
"Upload failed, please try again"; |
||||
} |
||||
// parse the vCard file |
||||
else if ($conv->fromFile($_FILES['_vcards']['tmp_name'])) |
||||
{ |
||||
$ext = $_POST['_format'] == 'gmail' ? 'csv' : ($_POST['_format'] == 'img' ? 'zip' : $_POST['_format']); |
||||
$fname = asciiwords(preg_replace('/\.[a-z]+$/i', '', $_FILES['_vcards']['name'])); |
||||
|
||||
header(sprintf('Content-Type: text/%s', $ext)); |
||||
header(sprintf('Content-Disposition: attachment; filename="%s.%s"', $fname, $ext)); |
||||
|
||||
if ($_POST['_format'] == 'ldif') |
||||
{ |
||||
print $conv->toLdif(); |
||||
exit; |
||||
} |
||||
else if ($_POST['_format'] == 'ldap') |
||||
{ |
||||
// Clean the input dn modifier from dangerous chars |
||||
$dnID = substr(preg_replace('/[^\da-z=,_ -]/i', '', $_POST['_dn']), 0, 255); |
||||
print $conv->toLdif($dnID ? $dnID : "", null, $_POST['_encoding']); |
||||
exit; |
||||
} |
||||
else if ($_POST['_format'] == 'gmail') |
||||
{ |
||||
print $conv->toGmail(); |
||||
exit; |
||||
} |
||||
else if ($_POST['_format'] == 'fritzbox') |
||||
{ |
||||
print $conv->toFritzBox(); |
||||
exit; |
||||
} |
||||
else if ($_POST['_format'] == 'csv') |
||||
{ |
||||
$header = $_POST['_header'] === '1' ? true : false; |
||||
$delimiter = $_POST['_delimiter'] == 'tab' ? "\t" : $_POST['_delimiter']; |
||||
print $conv->toCSV($delimiter, $header, $_POST['_encoding'], $_POST['_newlines']); |
||||
exit; |
||||
} |
||||
// extract all images from the vcard file |
||||
else if ($_POST['_format'] == 'img') |
||||
{ |
||||
mkdir($tmpdir = __DIR__ . '/tmp/'.md5(mt_rand())); // Diretory safe naming |
||||
if ($conv->toImages($tmpdir)) |
||||
{ |
||||
shell_exec('cd ' . escapeshellarg($tmpdir) . "; zip $fname *"); |
||||
$zipfile = "$tmpdir/$fname.zip"; |
||||
} |
||||
if ($zipfile && is_readable($zipfile)) |
||||
{ |
||||
header('Content-Type: application/zip', true); |
||||
readfile($zipfile); |
||||
$success = true; |
||||
} |
||||
else |
||||
{ |
||||
$GLOBALS['error_msg'] = "No images were found in this file."; |
||||
header('Content-Type: text/html', true); |
||||
header('Content-Disposition: inline', true); |
||||
} |
||||
|
||||
shell_exec('rm -rf '.escapeshellarg($tmpdir)); |
||||
|
||||
if ($success) |
||||
exit; |
||||
} |
||||
} |
||||
else |
||||
$GLOBALS['error_msg'] = "Could not parse vCard file. Either it is empty or of a format not supported."; |
||||
} |
||||
|
||||
|
||||
include('page.html'); |
||||
?> |
||||
@ -0,0 +1,240 @@
@@ -0,0 +1,240 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"> |
||||
<html> |
||||
<head> |
||||
<title>Online vCard Converter</title> |
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> |
||||
<meta name="keywords" content="vcard,vcf,ldif,ldap,csv,gmail,convert,mac,addresses,contacts,export,import" /> |
||||
<meta name="description" content="Convert your vCard files to CSV or LDIF in order to import them to Gmail (like A to G) or Outlook" /> |
||||
<style type="text/css"> |
||||
|
||||
body { |
||||
margin: 1em; |
||||
background: #fff; |
||||
font-family:'Lucida Grande', Geneva, Verdana, Arial, Helvetica, sans-serif; |
||||
font-size: small; |
||||
} |
||||
|
||||
td.cell { |
||||
background:#efefef; |
||||
padding-right: 0.6em; |
||||
} |
||||
|
||||
td.label { |
||||
color: #333; |
||||
font-weight: bold; |
||||
text-align: right; |
||||
} |
||||
|
||||
.title { |
||||
font-size:20px; |
||||
font-weight:bold; |
||||
} |
||||
|
||||
.hint { |
||||
color: #999999; |
||||
} |
||||
|
||||
.error { |
||||
color: #cc0000; |
||||
} |
||||
|
||||
.disclaimer { |
||||
width: 48em; |
||||
color: #333; |
||||
font-size: 0.9em; |
||||
border: 1px solid #cc6; |
||||
background: #ffd; |
||||
margin-top: 1em; |
||||
padding: 1em; |
||||
} |
||||
|
||||
.disclaimer h4 { |
||||
margin-top: 0; |
||||
} |
||||
|
||||
</style> |
||||
<script type="text/javascript"> |
||||
|
||||
function set_form_fields(elem) |
||||
{ |
||||
var format = elem.options[elem.selectedIndex].value; |
||||
var header = elem.form._header; |
||||
var delimiter = elem.form._delimiter; |
||||
var encoding = elem.form._encoding; |
||||
var newlines = elem.form._newlines; |
||||
var dn = elem.form._dn; |
||||
|
||||
switch (format) |
||||
{ |
||||
case 'gmail': |
||||
encoding.selectedIndex = 0; |
||||
newlines.selectedIndex = 0; |
||||
|
||||
case 'ldif': |
||||
case 'img': |
||||
header.disabled = true; |
||||
delimiter.disabled = true; |
||||
encoding.disabled = true; |
||||
newlines.disabled = true; |
||||
dn.disabled = true; |
||||
break; |
||||
|
||||
case 'ldap': |
||||
header.disabled = true; |
||||
delimiter.disabled = true; |
||||
encoding.disabled = false; |
||||
newlines.disabled = true; |
||||
dn.disabled = false; |
||||
break; |
||||
|
||||
case 'csv': |
||||
header.disabled = false; |
||||
delimiter.disabled = false; |
||||
encoding.disabled = false; |
||||
newlines.disabled = false; |
||||
dn.disabled = true; |
||||
break; |
||||
|
||||
case 'fritzbox': |
||||
encoding.selectedIndex = 1; |
||||
delimiter.selectedIndex = 1; |
||||
newlines.selectedIndex = 2; |
||||
header.checked = true; |
||||
header.disabled = true; |
||||
delimiter.disabled = true; |
||||
encoding.disabled = true; |
||||
newlines.disabled = true; |
||||
dn.disabled = true; |
||||
break; |
||||
} |
||||
|
||||
var rootdnrow = document.getElementById('ldaprootdn'); |
||||
rootdnrow.style.display = dn.disabled ? 'none' : (document.all && !window.opera ? 'block' : 'table-row'); |
||||
} |
||||
|
||||
</script> |
||||
</head> |
||||
<body> |
||||
|
||||
<form method="post" action="index.php" enctype="multipart/form-data"> |
||||
|
||||
<table border="0" cellspacing="0" cellpadding="0"><tr> |
||||
|
||||
<td width="180" height="90"><img src="vcf2csv_logo.jpg" width="170" height="78" alt="VCard to CSV Logo"></td> |
||||
<td class="title">vCard to LDIF/CSV Converter</td> |
||||
|
||||
</tr></table> |
||||
|
||||
<p>Preferred to export Apple's Address Book to Mozilla Thunderbird.<br /> |
||||
<span class="hint">Simply drag all contacts from the Address Book to your desktop and upload the created vCard file.</span></p> |
||||
|
||||
<?php |
||||
|
||||
if (!empty($GLOBALS['error_msg'])) |
||||
print '<p class="error">'.$GLOBALS['error_msg']."</p>\n"; |
||||
|
||||
?> |
||||
|
||||
<table border="0" cellspacing="1" cellpadding="2"><tr> |
||||
|
||||
<td class="cell label">vCard-File:</td> |
||||
<td class="cell"><input type="file" size="30" name="_vcards"> |
||||
<span class="hint" style="padding-left:1em">(max. <?php echo show_bytes(parse_bytes(ini_get('upload_max_filesize'))); ?>)</span></td> |
||||
|
||||
</tr><tr> |
||||
|
||||
<td class="cell label">Format:</td> |
||||
<td class="cell"><select name="_format" onChange="set_form_fields(this)"> |
||||
<option value="ldif">LDIF (Mozilla Thunderbird)</option> |
||||
<option value="ldap">LDIF (Import to LDAP server)</option> |
||||
<option value="csv">CSV</option> |
||||
<option value="gmail">Gmail (CSV)</option> |
||||
<option value="fritzbox">FritzBox (CSV)</option> |
||||
<option value="img">Images</option> |
||||
</select> |
||||
<select name="_delimiter" disabled> |
||||
<option value="tab">Tab</option> |
||||
<option value=";">Semicolon</option> |
||||
<option value=",">Comma</option> |
||||
</select> |
||||
<input type="checkbox" name="_header" id="checkHeader" value="1" disabled><label for="checkHeader"> Add header line</label></td> |
||||
|
||||
</tr><tr id="ldaprootdn" style="display:none"> |
||||
|
||||
<td class="cell label">Root DN:</td> |
||||
<td class="cell"> |
||||
<input type="text" name="_dn" id="dnID" style="width:30em;" disabled> |
||||
<label for="accessCode"><br>Use as Root DN LDAP identifier, to add it at the end of the "dn:" LDIF line <br>(for example: dc=Users, dc=nodomain)</label> |
||||
<span class="hint" style="padding-left:1em">(max. 255 chars)</span> |
||||
</td> |
||||
|
||||
</tr><tr> |
||||
|
||||
<td class="cell label">Encoding:</td> |
||||
<td class="cell"> |
||||
<select name="_encoding" disabled> |
||||
<option value="UTF-8" selected>Unicode (UTF-8)</option> |
||||
<option value="UTF-16LE">Unicode (UTF-16LE)</option> |
||||
<option value="ISO-8859-1">Windows Latin-1 (ISO-8859-1)</option> |
||||
<option value="ISO-8859-15">Windows Latin-9 (ISO-8859-15)</option> |
||||
<option value="MS-ANSI">Microsoft ANSI (Windows-1252)</option> |
||||
<!--<option value="MacRoman">Macintosh (Mac Roman)</option>--> |
||||
</select> |
||||
<select name="_newlines" disabled> |
||||
<option value="lf" selected>Line Feed (Default)</option> |
||||
<option value="cr">Carriage Return (old Mac OS)</option> |
||||
<option value="crlf">CR-LF (Windows)</option> |
||||
</select> |
||||
</td> |
||||
|
||||
</tr><tr valign="top"> |
||||
|
||||
<td class="cell label">Filter:</td> |
||||
<td class="cell"> |
||||
<input type="checkbox" name="_mailonly" id="checkMailonly" value="1"><label for="checkMailonly"> vCards with e-mail only</label><br /> |
||||
<input type="checkbox" name="_phoneonly" id="checkPhoneonly" value="1"><label for="checkPhoneonly"> vCards with phone numbers only</label> |
||||
</td> |
||||
|
||||
</tr><tr> |
||||
|
||||
<td class="cell label">Modifications:</td> |
||||
<td class="cell"> |
||||
<input type="text" name="_accesscode" id="accessCode" style="width:3em;"> |
||||
<label for="accessCode">replace this International Access Code with «0»</label> |
||||
</td> |
||||
|
||||
</tr><tr> |
||||
|
||||
<td></td> |
||||
<td><br><input type="submit" value="convert"></td> |
||||
|
||||
</tr></table> |
||||
</form> |
||||
|
||||
<div class="disclaimer"> |
||||
<h4>How to convert files</h4> |
||||
|
||||
<ol> |
||||
<li>Select a file from your computer's local drive for the field "vCard-File"</li> |
||||
<li>Choose the desired output format</li> |
||||
<li>Click the "convert" button</li> |
||||
</ol> |
||||
|
||||
<p>The converted file is automatically downloaded to your computer. |
||||
If you're not prompted where to save the file, you'll find it in the "Downloads" folder on your computer.</p> |
||||
|
||||
<h4>Privacy Policy</h4> |
||||
|
||||
<p>This public service is intended to provide simple functions to convert any vCard file into another format. |
||||
It was created for personal needs and is now provided on a private and non commercial basis. |
||||
The uploaded file will not be stored permanently nor will the converted addresses be kept on the server.</p> |
||||
|
||||
<p>You can also <a href="https://github.com/thomascube/vcfconvert/releases">download</a> the script |
||||
and run it locally. All you need is a webserver or a shell with PHP installed. This software is free and open source |
||||
and everybody is welcome to help us improving it. Fork us on <a href="https://github.com/thomascube/vcfconvert">github</a>!</p> |
||||
|
||||
<p>For questions about development, privacy or security, please contact tellme@brotherli.ch</p> |
||||
</div> |
||||
|
||||
</body> |
||||
</html> |
||||
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
Order allow,deny |
||||
Deny from all |
||||
@ -0,0 +1,70 @@
@@ -0,0 +1,70 @@
|
||||
<?php |
||||
|
||||
/** |
||||
* Parse a human readable string for a number of bytes |
||||
* |
||||
* @param string Input string |
||||
* @return int Number of bytes |
||||
*/ |
||||
function parse_bytes($str) |
||||
{ |
||||
if (is_numeric($str)) |
||||
return intval($str); |
||||
|
||||
if (preg_match('/([0-9]+)([a-z])/i', $str, $regs)) |
||||
{ |
||||
$bytes = floatval($regs[1]); |
||||
switch (strtolower($regs[2])) |
||||
{ |
||||
case 'g': |
||||
$bytes *= 1073741824; |
||||
break; |
||||
case 'm': |
||||
$bytes *= 1048576; |
||||
break; |
||||
case 'k': |
||||
$bytes *= 1024; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return intval($bytes); |
||||
} |
||||
|
||||
/** |
||||
* Create a human readable string for a number of bytes |
||||
* |
||||
* @param int Number of bytes |
||||
* @return string Byte string |
||||
*/ |
||||
function show_bytes($bytes) |
||||
{ |
||||
if ($bytes > 1073741824) |
||||
{ |
||||
$gb = $bytes/1073741824; |
||||
$str = sprintf($gb >= 10 || $gb-intval($gb) == 0 ? "%d GB" : "%.1f GB", $gb); |
||||
} |
||||
else if ($bytes > 1048576) |
||||
{ |
||||
$mb = $bytes/1048576; |
||||
$str = sprintf($mb >= 10 || $mb-intval($mb) == 0 ? "%d MB" : "%.1f MB", $mb); |
||||
} |
||||
else if ($bytes > 1024) |
||||
$str = sprintf("%d KB", round($bytes/1024)); |
||||
else |
||||
$str = sprintf('%d B', $bytes); |
||||
|
||||
return $str; |
||||
} |
||||
|
||||
/** |
||||
* Remove all non-ascii and non-word chars |
||||
* except . and - |
||||
*/ |
||||
function asciiwords($str) |
||||
{ |
||||
return preg_replace(array('/\s+/', '/[^a-z0-9\_\-\.]/i'), array('_',''), $str); |
||||
} |
||||
|
||||
|
||||
?> |
||||
|
After Width: | Height: | Size: 5.4 KiB |
@ -0,0 +1,141 @@
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env php -qC |
||||
<?php |
||||
|
||||
/* |
||||
+-----------------------------------------------------------------------+ |
||||
| Commandline vCard converter | |
||||
| Version 0.9.0 | |
||||
| | |
||||
| Copyright (C) 2006-2013, Thomas Bruederli - Switzerland | |
||||
| Licensed under the GNU GPL | |
||||
| | |
||||
| Type './vcfconvert.sh help' for usage information | |
||||
| | |
||||
+-----------------------------------------------------------------------+ |
||||
| Author: Thomas Bruederli <thomas@brotherli.ch> | |
||||
+-----------------------------------------------------------------------+ |
||||
|
||||
*/ |
||||
|
||||
@ini_set('error_reporting', E_ALL &~ E_NOTICE); |
||||
|
||||
require_once('vcard_convert.php'); |
||||
require_once('utils.php'); |
||||
|
||||
/** |
||||
* Parse commandline arguments into a hash array |
||||
*/ |
||||
function get_args() |
||||
{ |
||||
$args = array(); |
||||
for ($i=1; $i<count($_SERVER['argv']); $i++) |
||||
{ |
||||
$arg = $_SERVER['argv'][$i]; |
||||
if ($arg[0] == '-' && $arg[1] != '-') |
||||
{ |
||||
for ($j=1; $j < strlen($arg); $j++) |
||||
{ |
||||
$key = $arg[$j]; |
||||
$value = $_SERVER['argv'][$i+1]{0} != '-' ? preg_replace(array('/^["\']/', '/["\']$/'), '', $_SERVER['argv'][++$i]) : true; |
||||
$args[$key] = $value; |
||||
} |
||||
} |
||||
else |
||||
$args[] = $arg; |
||||
} |
||||
|
||||
return $args; |
||||
} |
||||
|
||||
// read commandline arguments |
||||
$opt = get_args(); |
||||
$usage = <<<EOF |
||||
Usage: vcfconvert.sh [-hilmpv] [-d delimiter] [-c utf-8] [-b identifier] [-o output_file] -f format <file> |
||||
-f Target format (ldif,ldap,csv,gmail,libdlusb,fritzbox,img) |
||||
-b LDAP identifier added to dn: |
||||
-l Generate just a list of DN objects (only works with -b) |
||||
-o Output file (write to stdout by default) |
||||
-d CSV col delimiter |
||||
-h Include header line in CSV output |
||||
-i Convert CSV output to ISO-8859-1 encoding (deprecated, use -c instead) |
||||
-c Character encoding for CSV output |
||||
-n Line endings for CSV output: 'n', 'r' or 'rn' |
||||
-m Only convert cards with an e-mail address |
||||
-p Only convert cards with phone numbers |
||||
-v Verbose output |
||||
|
||||
EOF; |
||||
|
||||
// show help |
||||
if ($opt[0] == 'help') |
||||
die($usage); |
||||
|
||||
// read arguments |
||||
$file = array_pop($opt); |
||||
$format = $opt['f'] ? $opt['f'] : 'ldif'; |
||||
|
||||
if (empty($file)) |
||||
die("Not enough arguments!\n$usage"); |
||||
|
||||
// instantiate a parser object |
||||
$conv = new vcard_convert(array('mailonly' => isset($opt['m']), 'phoneonly' => isset($opt['p']))); |
||||
|
||||
// parse a vCard file |
||||
if ($conv->fromFile($file)) |
||||
{ |
||||
if (isset($opt['v'])) |
||||
echo "Detected $conv->file_charset encoding\n"; |
||||
if (isset($opt['v']) && isset($opt['m'])) |
||||
echo "Only convert vCards with an e-mail address\n"; |
||||
|
||||
if ($format == 'ldif') |
||||
$out = $conv->toLdif(); |
||||
|
||||
else if ($format == 'ldap') |
||||
$out = $conv->toLdif($opt['b'], isset($opt['l']) ? 'dn' : null); |
||||
|
||||
else if ($format == 'gmail') |
||||
$out = $conv->toGmail(); |
||||
|
||||
else if ($format == 'libdlusb') |
||||
$out = $conv->toLibdlusb(); |
||||
|
||||
else if ($format == 'fritzbox') |
||||
$out = $conv->toFritzBox(); |
||||
|
||||
else if ($format == 'csv') |
||||
{ |
||||
if (!isset($opt['c']) && isset($opt['i'])) |
||||
$opt['c'] = 'ISO-8859-1'; |
||||
$delimiter = isset($opt['d']) ? ($opt['d']=='\t' || $opt['d']=='tab' ? "\t" : $opt['d']) : ";"; |
||||
$out = $conv->toCSV($delimiter, isset($opt['h']), isset($opt['c']) ? strtoupper($opt['c']) : null, $opt['n']); |
||||
|
||||
if (isset($opt['v']) && isset($opt['c'])) |
||||
echo "Converting output to " . strtoupper($opt['c']) . PHP_EOL; |
||||
} |
||||
else if ($format == 'img') |
||||
$out = $conv->toImages('tmp'); |
||||
|
||||
else |
||||
die("Unknown output format\n"); |
||||
|
||||
// write to output file |
||||
if ($opt['o']) |
||||
{ |
||||
if ($fp = @fopen($opt['o'], 'w')) |
||||
{ |
||||
fwrite($fp, $out); |
||||
fclose($fp); |
||||
echo "Wrote ".$conv->export_count." cards to $opt[o]\n"; |
||||
} |
||||
else |
||||
die("Cannot write to $opt[o]; permission denied\n"); |
||||
} |
||||
else |
||||
echo $out; |
||||
} |
||||
else |
||||
echo "Cannot parse $file\n"; |
||||
|
||||
|
||||
?> |
||||
Loading…
Reference in new issue