mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-22 16:51:42 +00:00
BanEntry: work around stupid bug in ext/date
https://bugs.php.net/bug.php?id=75992 When plugins do time-limited bans and users enter stupid time values, a shitty bug in ext/date gets triggered, but only when reading the ban entries from disk. DateTime->format() is able to produce formatted strings which have more than 4 digits in the year, which are then considered invalid. This works around it by trying to parse a formatted version on the fly to ensure that it is valid. This also cleans up and improves ban list loading and handling.
This commit is contained in:
parent
aa11dbb928
commit
37e8c8d324
@ -56,6 +56,7 @@ class BanEntry{
|
||||
}
|
||||
|
||||
public function setCreated(\DateTime $date){
|
||||
self::validateDate($date);
|
||||
$this->creationDate = $date;
|
||||
}
|
||||
|
||||
@ -78,6 +79,9 @@ class BanEntry{
|
||||
* @param \DateTime|null $date
|
||||
*/
|
||||
public function setExpires(\DateTime $date = null){
|
||||
if($date !== null){
|
||||
self::validateDate($date);
|
||||
}
|
||||
$this->expirationDate = $date;
|
||||
}
|
||||
|
||||
@ -110,37 +114,71 @@ class BanEntry{
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hacky function to validate \DateTime objects due to a bug in PHP. format() with "Y" can emit years with more than
|
||||
* 4 digits, but createFromFormat() with "Y" doesn't accept them if they have more than 4 digits on the year.
|
||||
*
|
||||
* @link https://bugs.php.net/bug.php?id=75992
|
||||
*
|
||||
* @param \DateTime $dateTime
|
||||
* @throws \RuntimeException if the argument can't be parsed from a formatted date string
|
||||
*/
|
||||
private static function validateDate(\DateTime $dateTime) : void{
|
||||
self::parseDate($dateTime->format(self::$format));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
*
|
||||
* @return \DateTime|null
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private static function parseDate(string $date) : ?\DateTime{
|
||||
$datetime = \DateTime::createFromFormat(self::$format, $date);
|
||||
if(!($datetime instanceof \DateTime)){
|
||||
throw new \RuntimeException("Error parsing date for BanEntry: " . implode(", ", \DateTime::getLastErrors()["errors"]));
|
||||
}
|
||||
|
||||
return $datetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
*
|
||||
* @return BanEntry|null
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function fromString(string $str){
|
||||
public static function fromString(string $str) : ?BanEntry{
|
||||
if(strlen($str) < 2){
|
||||
return null;
|
||||
}else{
|
||||
$str = explode("|", trim($str));
|
||||
$entry = new BanEntry(trim(array_shift($str)));
|
||||
if(count($str) > 0){
|
||||
$datetime = \DateTime::createFromFormat(self::$format, array_shift($str));
|
||||
if(!($datetime instanceof \DateTime)){
|
||||
MainLogger::getLogger()->alert("Error parsing date for BanEntry for player \"" . $entry->getName() . "\", the format may be invalid!");
|
||||
return $entry;
|
||||
do{
|
||||
if(empty($str)){
|
||||
break;
|
||||
}
|
||||
$entry->setCreated($datetime);
|
||||
if(count($str) > 0){
|
||||
$entry->setSource(trim(array_shift($str)));
|
||||
if(count($str) > 0){
|
||||
$expire = trim(array_shift($str));
|
||||
if(strtolower($expire) !== "forever" and strlen($expire) > 0){
|
||||
$entry->setExpires(\DateTime::createFromFormat(self::$format, $expire));
|
||||
}
|
||||
if(count($str) > 0){
|
||||
$entry->setReason(trim(array_shift($str)));
|
||||
}
|
||||
}
|
||||
|
||||
$entry->setCreated(self::parseDate(array_shift($str)));
|
||||
if(empty($str)){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$entry->setSource(trim(array_shift($str)));
|
||||
if(empty($str)){
|
||||
break;
|
||||
}
|
||||
|
||||
$expire = trim(array_shift($str));
|
||||
if(strtolower($expire) !== "forever" and strlen($expire) > 0){
|
||||
$entry->setExpires(self::parseDate($expire));
|
||||
}
|
||||
if(empty($str)){
|
||||
break;
|
||||
}
|
||||
|
||||
$entry->setReason(trim(array_shift($str)));
|
||||
}while(false);
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
@ -147,9 +147,15 @@ class BanList{
|
||||
if(is_resource($fp)){
|
||||
while(($line = fgets($fp)) !== false){
|
||||
if($line{0} !== "#"){
|
||||
$entry = BanEntry::fromString($line);
|
||||
if($entry instanceof BanEntry){
|
||||
$this->list[$entry->getName()] = $entry;
|
||||
try{
|
||||
$entry = BanEntry::fromString($line);
|
||||
if($entry instanceof BanEntry){
|
||||
$this->list[$entry->getName()] = $entry;
|
||||
}
|
||||
}catch(\Throwable $e){
|
||||
$logger = MainLogger::getLogger();
|
||||
$logger->critical("Failed to parse ban entry from string \"$line\": " . $e->getMessage());
|
||||
$logger->logException($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user