Detection of invalid sheet name

Based on Excel requirements:
 - it should not be blank
 - it should not exceed 31 characters
 - it should not contain these characters: \ / ? * [ or ]
 - it should be unique
This commit is contained in:
Adrien Loison committed 2015-08-21 15:21:36 -07:00
1 parent 366f121eb0
commit 7efab5576d
4 files changed
+234 -9

No files matched your search

@@ -0,0 +1,12 @@
<?php
namespace Box\Spout\Writer\Exception;
/**
* Class InvalidSheetNameException
*
* @package Box\Spout\Writer\Exception
*/
class InvalidSheetNameException extends WriterException
{
}
+117 -2
View File
@@ -2,9 +2,11 @@
namespace Box\Spout\Writer\XLSX;
use Box\Spout\Writer\Exception\InvalidSheetNameException;
/**
* Class Sheet
* Represents a worksheet within a XLSX file
* External representation of a worksheet within a XLSX file
*
* @package Box\Spout\Writer\XLSX
*/
@@ -12,6 +14,15 @@ class Sheet
{
const DEFAULT_SHEET_NAME_PREFIX = 'Sheet';
/** Sheet name should not exceed 31 characters */
const MAX_LENGTH_SHEET_NAME = 31;
/** @var array Invalid characters that cannot be contained in the sheet name */
private static $INVALID_CHARACTERS_IN_SHEET_NAME = ['\\', '/', '?', '*', '[', ']'];
/** @var array Associative array [SHEET_INDEX] => [SHEET_NAME] keeping track of sheets' name to enforce uniqueness */
protected static $SHEETS_NAME_USED = [];
/** @var int Index of the sheet, based on order of creation (zero-based) */
protected $index;
@@ -24,7 +35,7 @@ class Sheet
public function __construct($sheetIndex)
{
$this->index = $sheetIndex;
$this->name = self::DEFAULT_SHEET_NAME_PREFIX . ($sheetIndex + 1);
$this->setName(self::DEFAULT_SHEET_NAME_PREFIX . ($sheetIndex + 1));
}
/**
@@ -44,12 +55,116 @@ class Sheet
}
/**
* Sets the name of the sheet. Note that Excel has some restrictions on the name:
* - it should not be blank
* - it should not exceed 31 characters
* - it should not contain these characters: \ / ? * [ or ]
* - it should be unique
*
* @param string $name Name of the sheet
* @return Sheet
* @throws \Box\Spout\Writer\Exception\InvalidSheetNameException If the sheet's name is invalid.
*/
public function setName($name)
{
if (!$this->isNameValid($name)) {
$errorMessage = "The sheet's name is invalid. It did not meet at least one of these requirements:\n";
$errorMessage .= " - It should not be blank\n";
$errorMessage .= " - It should not exceed 31 characters\n";
$errorMessage .= " - It should not contain these characters: \\ / ? * [ or ]\n";
$errorMessage .= " - It should be unique";
throw new InvalidSheetNameException($errorMessage);
}
$this->name = $name;
self::$SHEETS_NAME_USED[$this->index] = $name;
return $this;
}
/**
* Returns whether the given sheet's name is valid.
* @see Sheet::setName for validity rules.
*
* @param string $name
* @return bool TRUE if the name is valid, FALSE otherwise.
*/
protected function isNameValid($name)
{
if (!is_string($name)) {
return false;
}
$nameLength = $this->getStringLength($name);
$hasValidLength = ($nameLength > 0 && $nameLength <= self::MAX_LENGTH_SHEET_NAME);
$containsInvalidCharacters = $this->doesContainInvalidCharacters($name);
$isNameUnique = $this->isNameUnique($name);
return ($hasValidLength && !$containsInvalidCharacters && $isNameUnique);
}
/**
* Returns the length of the given string.
* It uses the multi-bytes function is available.
* @see strlen
* @see mb_strlen
*
* @param string $string
* @return int
*/
protected function getStringLength($string)
{
return extension_loaded('mbstring') ? mb_strlen($string) : strlen($string);
}
/**
* Returns the position of the given character/substring in the given string.
* It uses the multi-bytes function is available.
* @see strpos
* @see mb_strpos
*
* @param string $string Haystack
* @param string $char Needle
* @return int Index of the char in the string if found (started at 0) or -1 if not found
*/
protected function getCharPosition($string, $char)
{
$position = extension_loaded('mbstring') ? mb_strpos($string, $char) : strpos($string, $char);
return ($position !== false) ? $position : -1;
}
/**
* Returns whether the given name contains at least one invalid character.
* @see Sheet::$INVALID_CHARACTERS_IN_SHEET_NAME for the full list.
*
* @param string $name
* @return bool TRUE if the name contains invalid characters, FALSE otherwise.
*/
protected function doesContainInvalidCharacters($name)
{
foreach (self::$INVALID_CHARACTERS_IN_SHEET_NAME as $invalidCharacter) {
if ($this->getCharPosition($name, $invalidCharacter) !== -1) {
return true;
}
}
return false;
}
/**
* Returns whether the given name is unique.
*
* @param string $name
* @return bool TRUE if the name is unique, FALSE otherwise.
*/
protected function isNameUnique($name)
{
foreach (self::$SHEETS_NAME_USED as $sheetIndex => $sheetName) {
if ($sheetIndex !== $this->index && $sheetName === $name) {
return false;
}
}
return true;
}
}