PHPExcel fast duplicate row - php

I have row with different styles for each cell. I need to duplicate it (copy text, style, size).
I was using following function to do it:
function copyRowFull(&$ws_from, &$ws_to, $row_from, $row_to) {
$ws_to->getRowDimension($row_to)->setRowHeight($ws_from->getRowDimension($row_from)->getRowHeight());
$lastColumn = $ws_from->getHighestColumn();
$rangeFrom = 'A'.$row_from.':'.$lastColumn.$row_from;
// copy text
$ws_to->fromArray($ws_from->rangeToArray($rangeFrom), null, 'A'.$row_to);
// copy style
++$lastColumn;
for ($c = 'A'; $c != $lastColumn; ++$c) {
$ws_to->duplicateStyle($ws_from->getStyle($c.$row_from), $c.$row_to);
}
}
However it it VERY slow due to loop but I need it fast because many rows will be copied.
Also I have tried this for style copying:
$rangeTo = 'A'.$row_to.':'.$lastColumn.$row_to;
$ws_to->getStyle($rangeTo)->applyFromArray($ws_from->getStyle($rangeFrom));
But it doesn't work - throws error "Invalid style array passed".
Is there any faster method?

After crawling in PHPExcel sources, I have figured out a lot faster way to duplicate row. It works copying only inside one workbook but it is what I needed. Posting it, maybe someone also had or will have similar problem.
function copyRowFull(&$ws_from, &$ws_to, $row_from, $row_to) {
$ws_to->getRowDimension($row_to)->setRowHeight($ws_from->getRowDimension($row_from)->getRowHeight());
$lastColumn = $ws_from->getHighestColumn();
++$lastColumn;
for ($c = 'A'; $c != $lastColumn; ++$c) {
$cell_from = $ws_from->getCell($c.$row_from);
$cell_to = $ws_to->getCell($c.$row_to);
$cell_to->setXfIndex($cell_from->getXfIndex()); // black magic here
$cell_to->setValue($cell_from->getValue());
}
}

For those on PHP 5.3 or so, Somnium's answer blended with Ravean's comment and adapted for PHP 5.3:
/**
* Copies entire row with formatting and merging
* #param $ws_from
* #param $ws_to
* #param $row_from
* #param $row_to
* #throws PHPExcel_Exception
*/
public function copyRowFull(&$ws_from, &$ws_to, $row_from, $row_to)
{
$ws_to->getRowDimension($row_to)->setRowHeight($ws_from->getRowDimension($row_from)->getRowHeight());
$lastColumn = $ws_from->getHighestColumn();
++$lastColumn;
for ($c = 'A'; $c != $lastColumn; ++$c) {
$cell_from = $ws_from->getCell($c . $row_from);
if ($cell_from->isMergeRangeValueCell()) {
$pCoordinateString = PHPExcel_Cell::splitRange($cell_from->getMergeRange());
$coordinateFromString = PHPExcel_Cell::coordinateFromString($pCoordinateString[0][1]);
$col = $coordinateFromString[0];
$ws_to->mergeCells($c . $row_to . ':' . $col . $row_to);
//$cell->getMergeRange()
}
$cell_to = $ws_to->getCell($c . $row_to);
$cell_to->setXfIndex($cell_from->getXfIndex()); // black magic here
$cell_to->setValue($cell_from->getValue());
}
}

Related

Generate multiple guid in PHP for firebase database

I have 70,000 rows in a MySQL table. I am trying to upload them in Firebase via import JSON. I have exported the table into JSON format. The output was an array. e.g., JSON is as follows -
[
{"question_id":"99","question":"What is your name?"},
{"question_id":"200","question":"What do you do?"}
]
For the correct use of Firebase in mobile apps, I need to import this JSON data as an object, along with GUID like following -
{
"-Lf64AvZinbjvEQLMzGc" : {
"question_id" : 99,
"question" : "What is your name?"
},
"-Lf64AvZinbjvEQLMzGd" : {
"question_id" : 200,
"question" : "What do you do?"
}
}
Since the number of rows are 70,000 (JSON file of this data is 110 MB); inserting individually into Firebase is not possible. So I was trying for a way to generate 70,000 GUID and editing the JSON file to add each one before every object. But, I am stuck at both places. I am using the following class (PushId.php) for generating GUID -
<?php
/**
* Fancy ID generator that creates 20-character string identifiers with the following properties:
*
* 1. They're based on timestamp so that they sort *after* any existing ids.
* 2. They contain 72-bits of random data after the timestamp so that IDs won't collide with other clients' IDs.
* 3. They sort *lexicographically* (so the timestamp is converted to characters that will sort properly).
* 4. They're monotonically increasing. Even if you generate more than one in the same timestamp, the
* latter ones will sort after the former ones. We do this by using the previous random bits
* but "incrementing" them by 1 (only in the case of a timestamp collision).
*/
class PushId
{
/**
* Modeled after base64 web-safe chars, but ordered by ASCII.
*
* #var string
*/
const PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
/**
* Timestamp of last push, used to prevent local collisions if you push twice in one ms.
*
* #var int
*/
private static $lastPushTime = 0;
/**
* We generate 72-bits of randomness which get turned into 12 characters and appended to the
* timestamp to prevent collisions with other clients. We store the last characters we
* generated because in the event of a collision, we'll use those same characters except
* "incremented" by one.
*
* #var array
*/
private static $lastRandChars = [];
/**
* #return string
*/
public static function generate()
{
$now = (int) microtime(true) * 1000;
$isDuplicateTime = ($now === static::$lastPushTime);
static::$lastPushTime = $now;
$timeStampChars = new SplFixedArray(8);
for ($i = 7; $i >= 0; $i--) {
$timeStampChars[$i] = substr(self::PUSH_CHARS, $now % 64, 1);
// NOTE: Can't use << here because javascript will convert to int and lose the upper bits.
$now = (int) floor($now / 64);
}
static::assert($now === 0, 'We should have converted the entire timestamp.');
$id = implode('', $timeStampChars->toArray());
if (!$isDuplicateTime) {
for ($i = 0; $i < 12; $i++) {
$lastRandChars[$i] = floor(rand(0, 64));
}
} else {
// If the timestamp hasn't changed since last push, use the same random number, except incremented by 1.
for ($i = 11; $i >= 0 && static::$lastRandChars[$i] === 63; $i--) {
static::$lastRandChars[$i] = 0;
}
static::$lastRandChars[$i]++;
}
for ($i = 0; $i < 12; $i++) {
$id .= substr(self::PUSH_CHARS, $lastRandChars[$i], 1);
}
static::assert(strlen($id) === 20, 'Length should be 20.');
return $id;
}
/**
* #param bool $condition
* #param string $message
*/
private static function assert($condition, $message = '')
{
if ($condition !== true) {
throw new RuntimeException($message);
}
}
}
Following is the PHP code that I wrote to generate 70,000 GUID but it showed error (while the same code is working if I use it to generate 1 GUID only)
require_once('PushId.php');
$vars = new PushId();
$my_file = 'TheGUIDs.txt';
$handle = fopen($my_file, 'w') or die('Cannot open file: '.$my_file);
$i=1;
while($i <= 70000){
$data = $vars->generate();
fwrite($handle, $data);
echo $data;
$i++;
}
fclose($handle);
Edit -1
The error I am getting in generating GUID is -
Notice: Undefined offset: 11 in C:\wamp64\www\firebase-json\PushId.php on line 65
Notice: Undefined variable: lastRandChars in C:\wamp64\www\firebase-json\PushId.php on line 71
The first GUID is complete, e.g. in last run I got -Lf8WPlkkNTUjYkIP4WT, but then I got incomplete GUID -Lf8WPlk------------
First, you forgot to prepend static:: to $lastRandChars in some places:
for ($i = 0; $i < 12; $i++) {
$lastRandChars[$i] = floor(rand(0, 64)); // << here
}
for ($i = 0; $i < 12; $i++) {
$id .= substr(self::PUSH_CHARS, $lastRandChars[$i], 1); // << and here
}
Next:
When incrementing previous ID, you missed that you should increment not only last char, but all previous chars as well if they are more than 63.
Sample IDs sequence:
...
-Lf64AvZinbjvEQLMzGw
-Lf64AvZinbjvEQLMzGx
-Lf64AvZinbjvEQLMzGy
-Lf64AvZinbjvEQLMzGz
-Lf64AvZinbjvEQLMzH- <<< on this step last char is reset, and previous one is incremented by one
-Lf64AvZinbjvEQLMzH0
-Lf64AvZinbjvEQLMzH1
...
-Lf64AvZinbjvEQLMzzw
-Lf64AvZinbjvEQLMzzx
-Lf64AvZinbjvEQLMzzw
-Lf64AvZinbjvEQLMzzz
-Lf64AvZinbjvEQLN--- <<< on this step last three chars are reset, and previous one is incremented by one
-Lf64AvZinbjvEQLN--0
-Lf64AvZinbjvEQLN--1
...
Modified increment logic:
// If the timestamp hasn't changed since last push, use the same random number, except incremented by 1.
for ($i = 11; $i >= 0; $i--) {
$previousIncremented = false;
for ($j = $i; $j > 0; $j--) {
if (!$previousIncremented) {
static::$lastRandChars[$j]++;
}
if (static::$lastRandChars[$j] == 64) {
static::$lastRandChars[$j] = 0;
static::$lastRandChars[$j - 1]++;
$previousIncremented = true;
} else {
break 2;
}
}
}

Magento 2 URL rewrite Issue : URL key already exists for specified store

I am facing this issue while saving a product programmatically on Magento 2.2.5
In any module, if I do $product->save(); OR $this->productRepository->save($product); inside a loop for multiple products. I get:
PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'the-lipstick.html-1' for key 'URL_REWRITE_REQUEST_PATH_STORE_ID' in /home/dev3/www/vendor/magento/zendframework1/library/Zend/Db/Statement/Pdo.php:228
The error is similar to the one described here : https://www.human-element.com/url-key-specified-store-already-exists-magento-2/
Products save fine with admin area login.
Any suggested fixes so far including the ones modifying the core files (DBStorage.php) do not work on 2.2.5.
What I tried so far:
1. Fix from https://www.human-element.com/url-key-specified-store-already-exists-magento-2/
2. Fix from https://magento.stackexchange.com/questions/210359/magento-2-product-url-rewrite-issue
Please suggest a solution/fix for M 2.2.5
My Fix :
In di.xml -
<preference for="Magento\UrlRewrite\Model\Storage\DbStorage" type="MyCompany\FixUrls\Model\ProductUrlFix" />
In ProductFixUrl write these two functions :
protected function doReplace(array $urls){
$this->deleteOld($urls);
$data = [];
$storeId_requestPaths = [];
foreach ($urls as $url) {
$storeId = $url->getStoreId();
$requestPath = $url->getRequestPath();
// Skip if is exist in the database
$sql = "SELECT * FROM url_rewrite where store_id = $storeId and request_path = '$requestPath'";
$exists = $this->connection->fetchOne($sql);
if ($exists) {
continue;
}
$storeId_requestPaths[] = $storeId . '-' . $requestPath;
$data[] = $url->toArray();
}
try {
$n = count($storeId_requestPaths);
for ($i = 0; $i < $n - 1; $i++) {
for ($j = $i + 1; $j < $n; $j++) {
if ($storeId_requestPaths[$i] == $storeId_requestPaths[$j]) {
unset($data[$j]);
}
}
}
parent::insertMultiple($data);
} catch (\Magento\Framework\Exception\AlreadyExistsException $e) {
/** #var \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[] $urlConflicted */
$urlConflicted = [];
foreach ($urls as $url) {
$urlFound = parent::doFindOneByData(
[
UrlRewriteData::REQUEST_PATH => $url->getRequestPath(),
UrlRewriteData::STORE_ID => $url->getStoreId(),
]
);
if (isset($urlFound[UrlRewriteData::URL_REWRITE_ID])) {
$urlConflicted[$urlFound[UrlRewriteData::URL_REWRITE_ID]] = $url->toArray();
}
}
if ($urlConflicted) {
throw new \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException(
__('URL key for specified store already exists.'),
$e,
$e->getCode(),
$urlConflicted
);
} else {
throw $e->getPrevious() ?: $e;
}
}
return $urls;
}
/**
* #param UrlRewrite[] $urls
*
* #return void
*/
public function deleteOld(array $urls)
{
$oldUrlsSelect = $this->connection->select();
$oldUrlsSelect->from(
$this->resource->getTableName(self::TABLE_NAME)
);
/** #var UrlRewrite $url */
foreach ($urls as $url) {
$oldUrlsSelect->orWhere(
$this->connection->quoteIdentifier(
UrlRewrite::ENTITY_TYPE
) . ' = ?',
$url->getEntityType()
);
$oldUrlsSelect->where(
$this->connection->quoteIdentifier(
UrlRewrite::ENTITY_ID
) . ' = ?',
$url->getEntityId()
);
$oldUrlsSelect->where(
$this->connection->quoteIdentifier(
UrlRewrite::STORE_ID
) . ' = ?',
$url->getStoreId()
);
}
// prevent query locking in a case when nothing to delete
$checkOldUrlsSelect = clone $oldUrlsSelect;
$checkOldUrlsSelect->reset(Select::COLUMNS);
$checkOldUrlsSelect->columns('count(*)');
$hasOldUrls = (bool) $this->connection->fetchOne($checkOldUrlsSelect);
if ($hasOldUrls) {
$this->connection->query(
$oldUrlsSelect->deleteFromSelect(
$this->resource->getTableName(self::TABLE_NAME)
)
);
}
}
After a migration and a week digging into the problem the only thing that worked for me was https://www.safemage.com/url-optimization-after-migration-magento-2.html
I had to downgrade to 2.2.7 to use it. It says it works on 2.3 but it does not.
After looking on internet for days i can't find exact solution of this.
Then i found if we change the URLKEY of the category it will not show this error so i have done this.
$category->setPath($parentCategory->getPath())
->setParentId($parentId)
->setName('test1')
->setIsActive(true)
->setUrlKey(rand(1,1000000000));
$category->save();
I use random function to add category in database with random no using ->setUrlKey(rand(1,1000000000)); you can add any thing in this like duplicate category name with some random no etc.
and errors gone if it helps you give an UP. thanks

Joomla Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM [duplicate]

This question already has answers here:
PHP expects T_PAAMAYIM_NEKUDOTAYIM?
(11 answers)
Closed 9 years ago.
I have building a web site but i have a error code and i couldnt fould a fix it
Error
Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM in /home/eneskura/public_html/administrator/components/com_tz_portfolio/helpers/tz_portfolio.php on line 42
line 42-
$class::addEntry(JText::('COM_TZ_PORTFOLIO_SUBMENU_GROUP_FIELDS'), 'index.php?option=com_tz_portfolio&view=fieldsgroup', $vName == 'fieldsgroup');
how i can i fix it?
Site: eneskuray.com php 5.2.17 litespeed
full php
<?php
// No direct access
defined('_JEXEC') or die;
class TZ_PortfolioHelper
{
public static $extension = 'com_content';
/**
* Configure the Linkbar.
*
* #param string $vName The name of the active view.
*
* #return void
* #since 1.6
*/
public static function addSubmenu($vName)
{
$class = 'JHtmlSidebar';
if(!COM_TZ_PORTFOLIO_JVERSION_COMPARE){
$class = 'JSubMenuHelper';
}
$class::addEntry( JText::_('COM_TZ_PORTFOLIO_SUBMENU_GROUP_FIELDS'), 'index.php?option=com_tz_portfolio&view=fieldsgroup', $vName == 'fieldsgroup');
$class::addEntry(
JText::_('COM_TZ_PORTFOLIO_SUBMENU_FIELDS'),
'index.php?option=com_tz_portfolio&view=fields',
$vName == 'fields'
);
$class::addEntry(
JText::_('COM_TZ_PORTFOLIO_SUBMENU_CATEGORIES'),
'index.php?option=com_tz_portfolio&view=categories',
$vName == 'categories');
$class::addEntry(
JText::_('COM_TZ_PORTFOLIO_SUBMENU_ARTICLES'),
'index.php?option=com_tz_portfolio&view=articles',
$vName == 'articles'
);
$class::addEntry(
JText::_('COM_TZ_PORTFOLIO_SUBMENU_FEATURED_ARTICLES'),
'index.php?option=com_tz_portfolio&view=featured',
$vName == 'featured'
);
$class::addEntry(
JText::_('COM_TZ_PORTFOLIO_SUBMENU_TAGS'),
'index.php?option=com_tz_portfolio&view=tags',
$vName == 'tags');
$class::addEntry(
JText::_('COM_TZ_PORTFOLIO_SUBMENU_USERS'),
'index.php?option=com_tz_portfolio&view=users',
$vName == 'users');
}
/**
* Gets a list of the actions that can be performed.
*
* #param int The category ID.
* #param int The article ID.
*
* #return JObject
* #since 1.6
*/
public static function getActions($categoryId = 0, $articleId = 0)
{
$user = JFactory::getUser();
$result = new JObject;
if (empty($articleId) && empty($categoryId)) {
$assetName = 'com_tz_portfolio';
}
elseif (empty($articleId)) {
$assetName = 'com_tz_portfolio.category.'.(int) $categoryId;
}
else {
$assetName = 'com_tz_portfolio.article.'.(int) $articleId;
}
$actions = array(
'core.admin', 'core.manage', 'core.create', 'core.edit', 'core.edit.own', 'core.edit.state', 'core.delete'
);
foreach ($actions as $action) {
$result->set($action, $user->authorise($action, $assetName));
}
return $result;
}
/**
* Applies the content tag filters to arbitrary text as per settings for current user group
* #param text The string to filter
* #return string The filtered string
*/
public static function filterText($text)
{
// Filter settings
$config = JComponentHelper::getParams('com_config');
$user = JFactory::getUser();
$userGroups = JAccess::getGroupsByUser($user->get('id'));
$filters = $config->get('filters');
$blackListTags = array();
$blackListAttributes = array();
$customListTags = array();
$customListAttributes = array();
$whiteListTags = array();
$whiteListAttributes = array();
$noHtml = false;
$whiteList = false;
$blackList = false;
$customList = false;
$unfiltered = false;
// Cycle through each of the user groups the user is in.
// Remember they are included in the Public group as well.
foreach ($userGroups as $groupId)
{
// May have added a group but not saved the filters.
if (!isset($filters->$groupId)) {
continue;
}
// Each group the user is in could have different filtering properties.
$filterData = $filters->$groupId;
$filterType = strtoupper($filterData->filter_type);
if ($filterType == 'NH') {
// Maximum HTML filtering.
$noHtml = true;
}
elseif ($filterType == 'NONE') {
// No HTML filtering.
$unfiltered = true;
}
else {
// Black, white or custom list.
// Preprocess the tags and attributes.
$tags = explode(',', $filterData->filter_tags);
$attributes = explode(',', $filterData->filter_attributes);
$tempTags = array();
$tempAttributes = array();
foreach ($tags as $tag)
{
$tag = trim($tag);
if ($tag) {
$tempTags[] = $tag;
}
}
foreach ($attributes as $attribute)
{
$attribute = trim($attribute);
if ($attribute) {
$tempAttributes[] = $attribute;
}
}
// Collect the black or white list tags and attributes.
// Each lists is cummulative.
if ($filterType == 'BL') {
$blackList = true;
$blackListTags = array_merge($blackListTags, $tempTags);
$blackListAttributes = array_merge($blackListAttributes, $tempAttributes);
}
elseif ($filterType == 'CBL') {
// Only set to true if Tags or Attributes were added
if ($tempTags || $tempAttributes) {
$customList = true;
$customListTags = array_merge($customListTags, $tempTags);
$customListAttributes = array_merge($customListAttributes, $tempAttributes);
}
}
elseif ($filterType == 'WL') {
$whiteList = true;
$whiteListTags = array_merge($whiteListTags, $tempTags);
$whiteListAttributes = array_merge($whiteListAttributes, $tempAttributes);
}
}
}
// Remove duplicates before processing (because the black list uses both sets of arrays).
$blackListTags = array_unique($blackListTags);
$blackListAttributes = array_unique($blackListAttributes);
$customListTags = array_unique($customListTags);
$customListAttributes = array_unique($customListAttributes);
$whiteListTags = array_unique($whiteListTags);
$whiteListAttributes = array_unique($whiteListAttributes);
// Unfiltered assumes first priority.
if ($unfiltered) {
// Dont apply filtering.
}
else {
// Custom blacklist precedes Default blacklist
if ($customList) {
$filter = JFilterInput::getInstance(array(), array(), 1, 1);
// Override filter's default blacklist tags and attributes
if ($customListTags) {
$filter->tagBlacklist = $customListTags;
}
if ($customListAttributes) {
$filter->attrBlacklist = $customListAttributes;
}
}
// Black lists take third precedence.
elseif ($blackList) {
// Remove the white-listed attributes from the black-list.
$filter = JFilterInput::getInstance(
array_diff($blackListTags, $whiteListTags), // blacklisted tags
array_diff($blackListAttributes, $whiteListAttributes), // blacklisted attributes
1, // blacklist tags
1 // blacklist attributes
);
// Remove white listed tags from filter's default blacklist
if ($whiteListTags) {
$filter->tagBlacklist = array_diff($filter->tagBlacklist, $whiteListTags);
}
// Remove white listed attributes from filter's default blacklist
if ($whiteListAttributes) {
$filter->attrBlacklist = array_diff($filter->attrBlacklist);
}
}
// White lists take fourth precedence.
elseif ($whiteList) {
$filter = JFilterInput::getInstance($whiteListTags, $whiteListAttributes, 0, 0, 0); // turn off xss auto clean
}
// No HTML takes last place.
else {
$filter = JFilterInput::getInstance();
}
$text = $filter->clean($text, 'html');
}
return $text;
}
}
ATTETION : some texts deleted for privacy.
The scope resolution operator (::) can only be used on a class referenced using a variable from PHP 5.3 -- you're using 5.2.
You'd have to do JHtmlSidebar::addEntry or JSubMenuHelper::addEntry; you can't do $class::addEntry.
JText::('COM_TZ_PORTFOLIO_SUBMENU_GROUP_FIELDS') is not calling a method. It should be:
JText::_('COM_TZ_PORTFOLIO_SUBMENU_GROUP_FIELDS')
See JText.
T_PAAMAYIM_NEKUDOTAYIM refers to the two colons in a row like this ::. Looking at your code sample:
$class::addEntry( JText::('COM_TZ_PORTFOLIO_SUBMENU_GROUP_FIELDS'), 'index.php?option=com_tz_portfolio&view=fieldsgroup', $vName == 'fieldsgroup');
I believe the issue is with JText::(. As per Joomla documentation that should be formatted with an underscore so it is JText::_( so your code would be:
$class::addEntry( JText::_('COM_TZ_PORTFOLIO_SUBMENU_GROUP_FIELDS'), 'index.php?option=com_tz_portfolio&view=fieldsgroup', $vName == 'fieldsgroup');
Not 100% clear on Joomla internals, but that underscore (_) is actually a function/method of some sort within the JText class. So when you were calling it as JText::( PHP choked because it had no idea what you were trying to do with JText. By adding that underscore (_), it will now actually call a function within a class & do what it has to do.

Read xls file using PHPExcel lib and get cell type

I read XLS file using PHPExcel. There is cells date column. that data column has two type of cells (Date and Text type cells).
I need to get view value of the cells in the XLS file. So before get value of the cell i want to decided whether that cell is Date cell or Text cell.
How can i get view value of the XLS file cells. Is There method like getCellType(), getViewValueOfCell() or any other method for get view value of cell?
Note: $cell->getType is not a real method in PHPExcel. this pseudo method.
please suggest best logic/method for bellow cell read.
// read view value form date column
if($cell->getType == 'Date'){
$array_data[$rowIndex][$cell->getColumn()] = PHPExcel_Style_NumberFormat::toFormattedString($cell->getCalculatedValue(), 'YYYY-MM-DD');
}
else if($cell->getType == 'Text'){
$array_data[$rowIndex][$cell->getColumn()] = $cell->getCalculatedValue();
}
this my all XLS read function
$objReader = new PHPExcel_Reader_Excel5();
$objReader->setReadDataOnly(true);
$objPHPExcel = $objReader->load($file_path);
$rowIterator = $objPHPExcel->getActiveSheet()->getRowIterator();
$array_data = array();
foreach ($rowIterator as $row) {
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false); // Loop all cells, even if it is not set
// if(1 == $row->getRowIndex ()) continue;//skip first row
$rowIndex = $row->getRowIndex();
$array_data[$rowIndex] = array('A' => '', 'B' => '', 'C' => '', 'D' => '');
foreach ($cellIterator as $cell) {
if ('A' == $cell->getColumn()) {
$array_data[$rowIndex][$cell->getColumn()] = $cell->getCalculatedValue();
} else if ('B' == $cell->getColumn()) {
$array_data[$rowIndex][$cell->getColumn()] = $cell->getCalculatedValue();
} else if ('C' == $cell->getColumn()) {
// read view value form date column
if($cell->getType == 'Date'){
$array_data[$rowIndex][$cell->getColumn()] = PHPExcel_Style_NumberFormat::toFormattedString($cell->getCalculatedValue(), 'YYYY-MM-DD');
}
else if($cell->getType == 'Text'){
$array_data[$rowIndex][$cell->getColumn()] = $cell->getCalculatedValue();
}
} else if ('D' == $cell->getColumn()) {
$array_data[$rowIndex][$cell->getColumn()] = $cell->getCalculatedValue();
}
}
}
The cell's getDataType() will return the datatype of the value contained in a cell
Valid datatypes are defined in PHPExcel_Cell_DataType:
const TYPE_STRING2 = 'str';
const TYPE_STRING = 's';
const TYPE_FORMULA = 'f';
const TYPE_NUMERIC = 'n';
const TYPE_BOOL = 'b';
const TYPE_NULL = 'null';
const TYPE_INLINE = 'inlineStr';
const TYPE_ERROR = 'e';
Note that there is no datatype for dates or times: dates/times are a datatype of float in MS Excel.
To identify whether a cell contains a date/time value you need to check the numberformat mask. To simplify this, the following methods are available in the PHPExcel_Shared_Date class to identify a numberformat mask as one that relates to a date/time
isDateTime()
/**
* Is a given cell a date/time?
*
* #param PHPExcel_Cell $pCell
* #return boolean
*/
isDateTimeFormat()
/**
* Is a given number format a date/time?
*
* #param PHPExcel_Style_NumberFormat $pFormat
* #return boolean
*/
isDateTimeFormatCode()
/**
* Is a given number format code a date/time?
*
* #param string $pFormatCode
* #return boolean
*/
The API documentation should have identified these for you

How could I parse gettext .mo files in PHP4 without relying on setlocale/locales at all?

I made a couple related threads but this is the one direct question that I'm seeking the answer for. My framework will use Zend_Translate if the php version is 5, otherwise I have to mimic the functionality for 4.
It seems that pretty much every implementation of gettext relies on setlocale or locales, I know there's a LOT of inconsistency across systems which is why I don't want to rely upon it.
I've tried a couple times to get the textdomain, bindtextdomain and gettext functions to work but I've always needed to invoke setlocale.
By the way, all the .mo files will be UTF-8.
Here's some reusable code to parse MO files in PHP, based on Zend_Translate_Adapter_Gettext:
<?php
class MoParser {
private $_bigEndian = false;
private $_file = false;
private $_data = array();
private function _readMOData($bytes)
{
if ($this->_bigEndian === false) {
return unpack('V' . $bytes, fread($this->_file, 4 * $bytes));
} else {
return unpack('N' . $bytes, fread($this->_file, 4 * $bytes));
}
}
public function loadTranslationData($filename, $locale)
{
$this->_data = array();
$this->_bigEndian = false;
$this->_file = #fopen($filename, 'rb');
if (!$this->_file) throw new Exception('Error opening translation file \'' . $filename . '\'.');
if (#filesize($filename) < 10) throw new Exception('\'' . $filename . '\' is not a gettext file');
// get Endian
$input = $this->_readMOData(1);
if (strtolower(substr(dechex($input[1]), -8)) == "950412de") {
$this->_bigEndian = false;
} else if (strtolower(substr(dechex($input[1]), -8)) == "de120495") {
$this->_bigEndian = true;
} else {
throw new Exception('\'' . $filename . '\' is not a gettext file');
}
// read revision - not supported for now
$input = $this->_readMOData(1);
// number of bytes
$input = $this->_readMOData(1);
$total = $input[1];
// number of original strings
$input = $this->_readMOData(1);
$OOffset = $input[1];
// number of translation strings
$input = $this->_readMOData(1);
$TOffset = $input[1];
// fill the original table
fseek($this->_file, $OOffset);
$origtemp = $this->_readMOData(2 * $total);
fseek($this->_file, $TOffset);
$transtemp = $this->_readMOData(2 * $total);
for($count = 0; $count < $total; ++$count) {
if ($origtemp[$count * 2 + 1] != 0) {
fseek($this->_file, $origtemp[$count * 2 + 2]);
$original = #fread($this->_file, $origtemp[$count * 2 + 1]);
$original = explode("\0", $original);
} else {
$original[0] = '';
}
if ($transtemp[$count * 2 + 1] != 0) {
fseek($this->_file, $transtemp[$count * 2 + 2]);
$translate = fread($this->_file, $transtemp[$count * 2 + 1]);
$translate = explode("\0", $translate);
if ((count($original) > 1) && (count($translate) > 1)) {
$this->_data[$locale][$original[0]] = $translate;
array_shift($original);
foreach ($original as $orig) {
$this->_data[$locale][$orig] = '';
}
} else {
$this->_data[$locale][$original[0]] = $translate[0];
}
}
}
$this->_data[$locale][''] = trim($this->_data[$locale]['']);
unset($this->_data[$locale]['']);
return $this->_data;
}
}
Ok, I basically ended up writing a mo file parser based on Zend's Gettext Adapter, as far as I know gettext is pretty much reliant upon the locale, so manually parsing the .mo file would save the hassle of running into odd circumstances with locale issues with setlocale. I also plan on parsing the Zend Locale data provided in the form of xml files.

Categories