added vcfconvert a php app hosted on a symfony container

pull/4/head
Tai 3 years ago
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">&nbsp;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>&nbsp;
<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">&nbsp;vCards with e-mail only</label><br />
<input type="checkbox" name="_phoneonly" id="checkPhoneonly" value="1"><label for="checkPhoneonly">&nbsp;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;">&nbsp;
<label for="accessCode">replace this International Access Code with &laquo;0&raquo;</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 &quot;vCard-File&quot;</li>
<li>Choose the desired output format</li>
<li>Click the &quot;convert&quot; 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 &quot;Downloads&quot; 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&#x0040;brotherli.&#099;&#104;</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…
Cancel
Save