<?php
/**
 * OXID CSV Export
 *
 * Exportscript für das exportieren von Artikeldaten in eine CSV-Datei.
 * 
 * @author Benjamin Roth [benjamin@esales-media.de]
 * @version 0.1.11.1.25
 * @copyright 2011 eSales Media [www.esales-media.de]
 * @package OXID-Export
 */

/* CONFIGURATION START */

define('ES_CSV_EXPORT_HASH', 'c0cc283ff8985384c0f43ff0d8f91708'); // MD5::bergstraesserwinzer
 
/**
 * DB Settings
 */
 
$DB = array
(
	'host'     => 'localhost:/tmp/mysql5.sock',
	'database' => 'db530504992',
	'username' => 'dbo530504992',
	'password' => 'Kh78886Fe45Sd'
);

/**
 * Load configuration or exit
 */
if (!isset($_GET['config']) && !isset($_SERVER['argv'][1]))
	die('No configuration file specified');

if (isset($_GET['config']))
{
	$config = basename($_GET['config']);
} else {
	$config = basename($_SERVER['argv'][1]);
}

if (!strlen($config) || !file_exists(dirname(__FILE__).'/conf/'.$config))
	die('Configuration file not found');

require_once(dirname(__FILE__).'/conf/'.$config);

if (!isset($CONFIG) || !isset($EXPORT))
	die('Missing configuration');

/* CONFIGURATION END */

/* OXID INIT START */

/**
 * Returns false.
 *
 * @return boolean
 */
error_reporting( E_ALL ^ E_NOTICE );
ini_set('display_errors',true);

define('OX_BASE_PATH', dirname(__FILE__) .'/../' ); 

// custom functions file 
require OX_BASE_PATH . 'bootstrap.php'; 

// error reporting level
error_reporting(E_ALL ^ E_NOTICE);

// Generic utility method file including autoloading definition
require_once OX_BASE_PATH . 'core/oxfunctions.php';

/* OXID INIT END */


/**
 * Export Class
 *
 * @package OXID-Export
 * @author  Benjamin Roth
 */
class Export extends oxUBase {
	
	protected $_aOrders= array();

	protected $_aArticles = array();

	protected $_aCategories = array();
	
	protected $db;
	
	protected $oOxidConfig;
	
	protected $currentArticle = array();

	protected $arrDefaultSettings = array
	(
		'field_encloser'     => '"',
		'field_terminator'   => ';',
		'escape_char'        => '\\',
		'filename'           => 'esm_export/csv/export.csv',
		'encoding'           => 'UTF-8',
		'stripHTML'          => true,
		'strictStrip'        => true,
		'doublets'           => true,
		'languageid'         => 0,
		'includeHeader'      => true,
		'activeOnly'         => true,
		'activeArticleField' => 'OXACTIVE',
		'activeCatField'     => 'OXACTIVE',
		'onStockOnly'        => false,
		'skipLastTerminator' => true,
		'noVariants'         => false,
		'excludeParent'      => true,
		'catPathSeparator'   => ">",
		'customSqlCondition' => '',
		'eol'                => 'LF',
		'notCancelledOnly'   => false,
		'cancelledOderField' => 'OXSTORNO',
);

	protected $arrConfig = array();

	protected $blnSkipTrim = false;

	public function __construct()
	{
		// Get shop config object
		$this->oOxidConfig = $this->getConfig();

		// Set job config
		$this->arrConfig = array_merge($this->arrDefaultSettings,(is_array($GLOBALS['CONFIG']) ? $GLOBALS['CONFIG'] : array()));
		
		// DB initialization
		$this->db = oxDb::getDb();
		$this->db->SetFetchMode(ADODB_FETCH_ASSOC);
//		$this->db->query("SET character_set_results = '".strtoupper($this->arrConfig['encoding'])."'");

		// Check config vars
		$blnNotCancelledOnly = ($this->arrConfig['notCancelled'] === true ? true : false);
		$blnCustomSqlCond = ($this->arrConfig['customSqlCondition'] ? true : false);

		$order_where = '';
		if (count($GLOBALS['EXPORT']['folders']['exclude']) > 0)
		{
			$order_excludes_array = array();
			foreach($GLOBALS['EXPORT']['folders']['exclude_ids'] as $folder)
			{
				$order_excludes_array[] = "'".strtoupper($folder)."'";
			}
			$order_excludes = implode(',',$order_excludes_array);
			$order_where .= ' AND oo.OXFOLDER NOT IN ('.$order_excludes.')';
		}
		if (count($GLOBALS['EXPORT']['folders']['include']) > 0)
		{
			$order_includes_array = array();
			foreach($GLOBALS['EXPORT']['folders']['include'] as $folder)
			{
				$order_includes_array[] = "'".strtoupper($folder)."'";
			}
			$order_includes = implode(',',$order_includes_array);
			$order_where .= ' AND oo.OXFOLDER IN ('.$order_includes.')';
		}
		if ($blnNotCancelledOnly)
		{
			$order_where .= ' AND oo.'.$this->arrConfig['cancelledOderField'].' = 1';
		}
		if ($blnCustomSqlCond)
		{
			$order_where .= ' AND '.$this->arrConfig['customSqlCondition'];
		}
		
		$sql = "SELECT oo.OXID, oo.OXUSERID FROM oxorder AS oo WHERE oo.oxesexported != 1".($order_where ? ' AND '.$order_where : '')." ORDER BY oo.OXORDERDATE";
//		$sql = "SELECT oo.OXID, oo.OXUSERID FROM oxorder AS oo".($order_where ? ' WHERE '.$order_where : '')." ORDER BY oo.OXORDERDATE";
		$rs = $this->db->execute($sql);

		while($rs && !$rs->EOF)
		{
			$arrRow = $rs->fetchRow();
			$this->_aOrders[] = array('user' => $arrRow['OXUSERID'], 'order' => $arrRow['OXID']);
		}


	}

	function __call($name, $arguments)
	{
		switch ($name)
		{
			case 'getConfigParam':
				return (array_key_exists($arguments[0],$this->arrConfig) ? $this->arrConfig[$arguments[0]] : false);
			break;

			case 'getJobConfig':
				return $this->arrConfig;
			break;

			default:
				throw new BadFunctionCallException('Method "'.$name.'" does not exist');
		}
	}


	/**
	 * function getCategory
	 *
	 * @return object
	 */
	function getCategory($oxid)
	{
		if (isset($this->_aCategories[$oxid]) && is_object($this->_aCategories[$oxid]))
			return $this->_aCategories[$oxid];
		
		$oCategory = oxNew('oxcategory');
		$oCategory->setLanguage($this->arrConfig['languageid']);
		$oCategory->load($oxid);

		$this->_aCategories[$oxid] = $oCategory;
		return $this->_aCategories[$oxid];
	}

	function getCategoryPath($oxid)
	{
		$arrPath = array();
		if (isset($this->_aCategories[$oxid]) && is_object($this->_aCategories[$oxid]))
		{
			$oCategory = &$this->_aCategories[$oxid];
		} else {
			$oCategory = oxNew('oxcategory');
			$oCategory->setLanguage($this->arrConfig['languageid']);
			$oCategory->load($oxid);

			$this->_aCategories[$oxid] = $oCategory;

		}

		$arrPath[] = trim($oCategory->oxcategories__oxtitle->value);

		if ($oCategory->oxcategories__oxparentid->value != 'oxrootid')
		{
			$arrPath = array_merge($arrPath,$this->getCategoryPath($oCategory->oxcategories__oxparentid->value));
		}

		return array_reverse($arrPath);
	}

	/**
	 * function replaceTags
	 *
	 * @return string
	 */
	protected function replaceTags($strBuffer)
	{
		//$tags = preg_split('/{{([^}]+)}}/', $strBuffer, -1, PREG_SPLIT_DELIM_CAPTURE);
		$tags = preg_split('/\{\{(([^\{\}]*|(?R))*)\}\}/', $strBuffer, -1, PREG_SPLIT_DELIM_CAPTURE);

		$strBuffer = '';
		$arrCache = array();

		for($_rit=0, $_cnt=count($tags); $_rit<$_cnt; $_rit+=3)
		{
			/*if (!isset($tags[$_rit+1]))
			{
				continue;
			}*/

			$strBuffer .= $tags[$_rit];
			$strTag = (isset($tags[$_rit+1]) ? $tags[$_rit+1] : '');

			// Skip empty tags
			if (!strlen($strTag))
			{
				continue;
			}

			// Load value from cache array
			if (isset($arrCache[$strTag]))
			{
				$strBuffer .= $arrCache[$strTag];
				continue;
			}

			// Run the replacement again if there are more tags (see #4402)
			if (strpos($strTag, '{{') !== false)
			{
				$strTag = $this->replaceTags($strTag);
			}

			$elements = explode('::', $strTag);

			$arrCache[$strTag] = '';

			// Replace tag
			switch (strtolower($elements[0]))
			{
				case 'parent':
					if (is_null($this->currentArticle['parent']))
					{
						if (is_null($this->currentArticle['article']))
						{
							$this->currentArticle['article'] = $this->currentArticle['orderarticle']->getArticle();
						}
						if (!is_null($this->currentArticle['article']))
						{
							$this->currentArticle['parent'] = $this->currentArticle['article']->getParentArticle();
						}
					}
					if (!is_null($this->currentArticle['parent']))
					{
						$arrCache[$strTag] = $this->currentArticle['parent']->{'oxarticles__'.strtolower($elements[1])}->value;
					}
					break;

				case 'article':
					if (is_null($this->currentArticle['article']))
					{
						$this->currentArticle['article'] = $this->currentArticle['orderarticle']->getArticle();
					}
					if (!is_null($this->currentArticle['article']))
					{
						$arrCache[$strTag] = $this->currentArticle['article']->{'oxarticles__' . strtolower($elements[1])}->value;
					}
					break;

				case 'orderarticle':
					$arrCache[$strTag] = $this->currentArticle['orderarticle']->{'oxorderarticles__'.strtolower($elements[1])}->value;
					break;

				case 'orderarticlepos':
					$arrCache[$strTag] = $this->currentArticle['orderarticlepos'];
					break;

				case 'order':
					$arrCache[$strTag] = $this->currentArticle['order']->{'oxorder__'.strtolower($elements[1])}->value;
					break;

				case 'user':
					$arrCache[$strTag] = $this->currentArticle['user']->{'oxuser__'.strtolower($elements[1])}->value;
					break;

				case 'inheritance':
					if (!$this->currentArticle['article']->{'oxarticles__'.strtolower($elements[1])}->value)
					{
						if (is_null($this->currentArticle['parent']))
						{
							if (is_null($this->currentArticle['article']))
							{
								$this->currentArticle['article'] = $this->currentArticle['orderarticle']->getArticle();
							}
							if (!is_null($this->currentArticle['article']))
							{
								$this->currentArticle['parent'] = $this->currentArticle['article']->getParentArticle();
							}
						}
						$arrCache[$strTag] = (!$this->currentArticle['parent'] ? '' : $this->currentArticle['parent']->{'oxarticles__'.strtolower($elements[1])}->value);
					} else {
						$arrCache[$strTag] = $this->currentArticle['article']->{'oxarticles__'.strtolower($elements[1])}->value;
					}
					break;

				case 'category':
					if (is_null($this->currentArticle['category']))
					{
						if (is_null($this->currentArticle['article']))
						{
							$this->currentArticle['article'] = $this->currentArticle['orderarticle']->getArticle();
						}
						if (!is_null($this->currentArticle['article']))
						{
							$this->currentArticle['category'] = $this->currentArticle['article']->getCategory();
						}
					}
					if (!is_null($this->currentArticle['category']))
					{
						$arrCache[$strTag] = $this->currentArticle['category']->{'oxcategories__' . strtolower($elements[1])}->value;
					}
					break;

				case 'categorypath':
					$arrCache[$strTag] = implode($this->arrConfig['catPathSeparator'],$this->getCategoryPath($this->currentArticle['category']->oxcategories__oxid->value));
					break;

				case 'crossselling':
					$oCrossSelling = $this->currentArticle['article']->getCrossSelling();
					$arrCrossSelling = array();
					if (!is_null($oCrossSelling) && $intLimit = $oCrossSelling->count())
					{
						if (isset($elements[1]))
						{
							$intLimit = intval($elements[1]);
						}

						$i=0;
						while ($oCrossSelling->valid() && $i < $intLimit)
						{
							if ($oCrossSelling->current()->getVariants())
							{
								$arrCrossSelling[] = $oCrossSelling->current()->oxarticles__oxartnum->value.'__parent';
							} else {
								$arrCrossSelling[] = $oCrossSelling->current()->oxarticles__oxartnum->value;
							}
							$oCrossSelling->next();
							$i++;
						}
					}
					$arrCache[$strTag] = implode(',',$arrCrossSelling);
					break;
					
				case 'db_foreign':
					if (isset($elements[1]) && isset($elements[2]) && ($chunks = explode('=',$elements[1])))
					{
						list($foreign_table, $foreign_field) = explode('.',$chunks[0]);
						$foreign_keyValue = $this->currentArticle['article']->{'oxarticles__'.strtolower($chunks[1])}->value;
						if (($sViewName = getViewName($foreign_table, $this->arrConfig['languageid'])))
						{
							$sDbValue = $this->db->getOne("select ".$elements[2]." from {$sViewName} where ".$foreign_field." = " . $this->db->quote($foreign_keyValue));

						} else {
							$sDbValue = $this->db->getOne("select ".$elements[2]." from {$foreign_table} where ".$foreign_field." = " . $this->db->quote($foreign_keyValue));

						}/* else {
							$sql = "SELECT * FROM ".$foreign_table." WHERE ".$foreign_field."='".$foreign_keyValue."'";

							$resSql = $this->db->execute($sql);

							$arrCache[$strTag] = ($resSql->recordCount() < 1) ? '' : $resSql->fields($elements[2]);
						}*/
						if ($sDbValue)
						{
							$oForeign = new oxField();
							$oForeign->setValue($sDbValue, oxField::T_RAW);

							$arrCache[$strTag] = $oForeign->value;
						}


						unset($resSql,$oForeign);
					}
					break;

				case 'link':
					switch(strtolower($elements[1]))
					{
						case 'article':
							if ( oxRegistry::getUtils()->seoIsActive() )
							{
								$arrCache[$strTag] = preg_replace('/(?<=\.html)\?.*$/', '', $this->currentArticle['article']->getMainLink());
							} else {
								$arrCache[$strTag] = $this->currentArticle['article']->getMainLink();
							}
							break;
						case 'category':
							if ( oxRegistry::getUtils()->seoIsActive() )
							{
								$arrCache[$strTag] = preg_replace('/(?<=\.html)\?.*$/', '', $this->currentArticle['category']->getMainLink());
							} else {
								$arrCache[$strTag] = $this->currentArticle['category']->getMainLink();
							}
							break;
					}
					break;

				case 'image':
					switch(strtolower($elements[1]))
					{
						case 'article':
							switch(strtolower($elements[2]))
							{
								case 'thumb':
									$arrCache[$strTag] = $this->currentArticle['article']->getThumbnailUrl();
									break;
								case 'icon':
									$arrCache[$strTag] = $this->currentArticle['article']->getIconUrl();
									break;
								default:
									$arrCache[$strTag] = ($this->currentArticle['article']->{'oxarticles__oxpic'.$elements[2]}->value ? $this->currentArticle['article']->getZoomPictureUrl(intval($elements[2])) : '');
									break;
							}
							break;
						case 'category':
							$arrCache[$strTag] = '';
							break;
					}
					break;

				case 'db_if':
					if (isset($elements[1]) && isset($elements[2]) && isset($elements[3]) && isset($elements[4]))
					{
						
						$db_value = $this->currentArticle['article']->{'oxarticles__'.strtolower($elements[1])}->value;
						if (isset($elements[5]))
						{
							$varVal = $elements[4];
							$varAltVal = $elements[5];
						} else {
							$varVal = $db_value;
							$varAltVal = $elements[4];
						}
						switch($elements[2])
						{
							case '>':
								$arrCache[$strTag] = ($db_value > $elements[3]) ? $varVal : $varAltVal;
								break;
							case '>=':
								$arrCache[$strTag] = ($db_value >= $elements[3]) ? $varVal : $varAltVal;
								break;
							case '<':
								$arrCache[$strTag] = ($db_value < $elements[3]) ? $varVal : $varAltVal;
								break;
							case '<=':
								$arrCache[$strTag] = ($db_value <= $elements[3]) ? $varVal : $varAltVal;
								break;
							case '=':
								$arrCache[$strTag] = ($db_value == $elements[3]) ? $varVal : $varAltVal;
								break;
							case '!=':
								$arrCache[$strTag] = ($db_value != $elements[3]) ? $varVal : $varAltVal;
								break;
						}
					}
					break;

				case 'not_empty':
					if (isset($elements[1]) && isset($elements[2]))
					{
						if ($elements[1])
						{
							$arrCache[$strTag] = $elements[2];
						} else {
							$arrCache[$strTag] = '';
						}
					}
					break;

				case 'fixval':
					$arrCache[$strTag] = $elements[1];
					break;

				case 'has_variants':
					if (isset($elements[1]) && isset($elements[2]))
					{
						$arrCache[$strTag] = ($this->currentArticle['hasVariants'] ? $elements[1] : $elements[2]);
					}
					break;

				case 'parse_smarty':
					$arrCache[$strTag] = oxRegistry::get("oxUtilsView")->parseThroughSmarty($elements[1], basename($this->arrConfig['filename']) . $this->arrConfig['languageid'], null, true);
					break;

				case 'fstring':
					if (isset($elements[1]) && isset($elements[2]))
					{
						$this->blnSkipTrim = true;
						//$strFstring = call_user_func_array("sprintf",array_slice($elements,1,2));
						$strFstring = sprintf($elements[1],$this->convert($elements[2]));
						if (isset($elements[3]))
						{
							$strFstring = substr($strFstring,0,$elements[3]);
						}
						$arrCache[$strTag] = $this->convert($strFstring,'utf-8');
					}
					break;

				case 'fdate':
					if (isset($elements[1]) && isset($elements[2]))
					{
						$oDate = new DateTime($elements[2]);
						if (is_object($oDate))
						$arrCache[$strTag] = $oDate->format($elements[1]);
					}
					break;

				case 'price':
					if (isset($elements[1]))
					{
						$oPrice = oxNew( 'oxPrice' );
						$blPriceNet = (bool) $this->getConfig()->getConfigParam('blShowNetPrice');
						if ($blPriceNet)
						{
							$oPrice->setNettoPriceMode();
						} else {
							$oPrice->setBruttoPriceMode();
						}

						$oPrice->setPrice(doubleval($elements[1]));

						if (isset($elements[2]))
						{
							switch ($elements[2])
							{
								case 'net':
								case 'netto':
									$arrCache[$strTag] = $oPrice->getNettoPrice();
									break;

								case 'gross':
								case 'brutto':
									$arrCache[$strTag] = $oPrice->getBruttoPrice();
									break;

								default:
									$arrCache[$strTag] = $oPrice->getPrice();
									break;
							}
						}
					}
					break;

				case 'oxcountry':
					if (isset($elements[1]) && isset($elements[2]))
					{
						$oCountry = oxNew('oxcountry');
						$oCountry->load($elements[2]);

						$arrCache[$strTag] = $oCountry->{'oxcountry__'.strtolower($elements[1])}->value;
					}
					break;

				case 'translate':
					if (isset($elements[1]) && isset($elements[2]))
					{
						if (isset($GLOBALS['EXPORT']['translate'][$elements[1]][$elements[2]]))
						{
							$arrCache[$strTag] = $GLOBALS['EXPORT']['translate'][$elements[1]][$elements[2]];
						}
					}
					break;

				case 'eval':
					if (isset($elements[1]))
					{
						ob_start();
						eval('echo ('.$elements[1].');');

						$arrCache[$strTag] = ob_get_contents();
						ob_end_clean();
					}
					break;
			}

			$strBuffer .= $arrCache[$strTag];
		}

		return $strBuffer;
	}
	
	protected function parseLine($arrArticle,$strFieldConf='fields')
	{

		$oArticle = oxNew('oxorderarticle');
		$oArticle->load($arrArticle['orderarticle']);
		$oOrder = oxNew('oxorder');
		$oOrder->load($arrArticle['order']);
		$oUser = oxNew('oxuser');
		$oUser->load($arrArticle['user']);

		$this->currentArticle = array
		(
			'order'           => $oOrder,
			'orderarticle'    => $oArticle,
			'orderarticlepos' => $arrArticle['orderarticlepos'],
			'user'            => $oUser,
			'article'         => null,
			'category'        => null,
			'parent'          => null
		);

		$this->blnSkipTrim = false;
		$strLine = '';
		$index = 0;
		foreach($GLOBALS['EXPORT'][$strFieldConf] as $field)
		{
			$field = $this->replaceTags($field);
			$field = $this->encapsulate($field, ($this->arrConfig['skipLastTerminator'] && ++$index == count($GLOBALS['EXPORT']['fields']) ? true : false));
//			$field = mb_convert_encoding($field, strtoupper($this->arrConfig['encoding']), 'UTF-8');
			$strLine .= $this->convert($field);
		}
		return $strLine.(strtoupper($this->arrConfig['eol']) == 'CRLF' ? "\r\n" : "\n");
	}
	
	public function encapsulate($strVal, $blnSkipTerminator=false)
	{
		$strSrcEncoding = mb_detect_encoding($strVal,"UTF-8,".$this->arrConfig['encoding'].",cp1252,cp1251,cp1250,iso-8859-1,iso-8859-15",true);

		if (!$this->blnSkipTrim)
		{
			$strVal = trim($strVal);
		}
		$strVal = preg_replace('/[\\n\\r]/', '<br />', $strVal);
		if ($this->arrConfig['stripHTML'])
		{
			if ($this->arrConfig['strictStrip']) {
				$strVal = preg_replace('/(<br\s*(|\/)\s*>)+/i', ' ', $strVal);
				$strVal = preg_replace('/(<p\s*(|\/)\s*>)+/i', ' ', $strVal);
				$strVal = strip_tags($strVal);
				$strVal = mb_convert_encoding($strVal, 'HTML-ENTITIES', $strSrcEncoding);
				if (!$this->blnSkipTrim)
				{
					$strVal = trim(preg_replace('/[\xa0\s]+/', ' ', $strVal));
				}
				$strVal = str_ireplace('&nbsp;','',$strVal);
			} else {
				$strVal = strip_tags($strVal,'<br><p>');
				$strVal = preg_replace('/(<br\s*(|\/)\s*>){2,}/', '<br>', $strVal);
			}
		}
		$strVal = str_replace($this->arrConfig['field_encloser'],$this->arrConfig['escape_char'].$this->arrConfig['field_encloser'],$strVal);
		if (strlen($strVal))
		{
			$strVal = preg_replace('/(^|$)/',$this->arrConfig['field_encloser'],$strVal);
		} else {
			$strVal = $this->arrConfig['field_encloser'].$this->arrConfig['field_encloser'];
		}
		
		return $strVal.($blnSkipTerminator ? '' : $this->arrConfig['field_terminator']);
	}

	protected function convert($strValue, $strCharset = null)
	{
		if (is_null($strCharset))
		{
			$strCharset = strtoupper($this->arrConfig['encoding']);
		} else {
			$strCharset = strtoupper($strCharset);
		}

		$strSrcEncoding = mb_detect_encoding($strValue,"UTF-8,".$this->arrConfig['encoding'].",cp1252,cp1251,cp1250,iso-8859-1,iso-8859-15",true);
		return ($strSrcEncoding == $strCharset) ? $strValue : mb_convert_encoding($strValue, $strCharset, $strSrcEncoding);
	}

	protected function getHeader()
	{
		$strHeader = '';
		$index = 0;
		foreach(array_keys($GLOBALS['EXPORT']['fields']) as $field)
		{
			$field = $this->encapsulate($field, ($this->arrConfig['skipLastTerminator'] && ++$index == count($GLOBALS['EXPORT']['fields']) ? true : false));
			$strHeader .= $this->convert($field);
		}
		return $strHeader."\n";
	}
	
	public function getCSV()
	{
		// echo 'Datensätze: '.count($this->arrDB)."\n";
		$strBuffer = ($this->arrConfig['includeHeader']) ? $this->getHeader() : '';
		foreach($this->arrDB as $this->arrRow)
		{
			$strBuffer .= $this->parseLine($this->arrRow);
		}
		return $strBuffer;
	}
	
	public function saveCSV()
	{
		$tmpname = sys_get_temp_dir().'/'.hash('crc32', uniqid(microtime()));
		$count = 0;

		if (count($this->_aOrders) < 1)
		{
			return $count;
		}

		//$fh = fopen($tmpname,"a");
		$fh = fopen(getShopBasePath() . $this->arrConfig['filename'],"a");
		
		fputs($fh,(($this->arrConfig['includeHeader']) ? $this->getHeader() : ''));

		foreach($this->_aOrders as $order)
		{
			$this->_aArticles = array();
			$sql = "SELECT OXID FROM oxorderarticles AS ooa WHERE ooa.OXORDERID = " . $this->db->quote($order['order']) . " ORDER BY ooa.OXARTNUM";
			$rs = $this->db->execute($sql);

			while ($rs && !$rs->EOF)
			{
				$arrRow = $rs->fetchRow();
				$this->_aArticles[] = array_merge($order,array('orderarticle'=>$arrRow['OXID'], 'orderarticlepos'=>count($this->_aArticles)+1));
			}

			foreach ($this->_aArticles as $article)
			{
				// echo $article['article']->oxarticles__oxtitle->value."\n";
				// echo $article['category']->oxcategories__oxtitle->value."\n\n";
				fputs($fh, $this->parseLine($article));
			}

			// Shipping costs
			$aShipping = $article;
			$aShipping['orderarticlepos'] = $aShipping['orderarticlepos']+1;
			fputs($fh, $this->parseLine($aShipping,'shipping'));

			$sql = "UPDATE oxorder SET oxesexported = 1 WHERE oxid = " . $this->db->quote($order['order']) . "";
			$rs = $this->db->execute($sql);

			$count += count($this->_aArticles);
		}
		
		fclose($fh);
		/*if (!rename($tmpname, getShopBasePath() . $this->arrConfig['filename']))
		{
			die('Export file could not be created');
		}*/
			
		return $count;
	}
}


$Export = new Export();
$intArticles = $Export->saveCSV();

header('Content-Type: text/plain; charset='.$Export->getConfigParam['encoding']);
echo "Items exported: " . $intArticles."\n";

$intMemory = memory_get_peak_usage(true);
$hrsize = function($intMemory) {
	$kilobyte = 1024;
	$megabyte = $kilobyte * 1024;
	$gigabyte = $megabyte * 1024;
	$terabyte = $gigabyte * 1024;
	$precision = 2;
	$bytes = $intMemory;

	if (($bytes >= 0) && ($bytes < $kilobyte)) {
		return $bytes . ' B';

	} elseif (($bytes >= $kilobyte) && ($bytes < $megabyte)) {
		return round($bytes / $kilobyte, $precision) . ' KB';

	} elseif (($bytes >= $megabyte) && ($bytes < $gigabyte)) {
		return round($bytes / $megabyte, $precision) . ' MB';

	} elseif (($bytes >= $gigabyte) && ($bytes < $terabyte)) {
		return round($bytes / $gigabyte, $precision) . ' GB';

	} elseif ($bytes >= $terabyte) {
		return round($bytes / $terabyte, $precision) . ' TB';
	} else {
		return $bytes . ' B';
	}
};

echo "Memory used for export: " . $hrsize($intMemory)."\n";