added vcfconvert a php app hosted on a symfony container
parent
aada470a8d
commit
06204140a3
@ -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 @@
|
||||
<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 @@
|
||||
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 @@
|
||||
<?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 @@
|
||||
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 @@
|
||||
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 @@
|
||||
<?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 @@
|
||||
<!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 @@
|
||||
Order allow,deny
|
||||
Deny from all
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
@ -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