mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-08 12:48:32 +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){
|
public function setCreated(\DateTime $date){
|
||||||
|
self::validateDate($date);
|
||||||
$this->creationDate = $date;
|
$this->creationDate = $date;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +79,9 @@ class BanEntry{
|
|||||||
* @param \DateTime|null $date
|
* @param \DateTime|null $date
|
||||||
*/
|
*/
|
||||||
public function setExpires(\DateTime $date = null){
|
public function setExpires(\DateTime $date = null){
|
||||||
|
if($date !== null){
|
||||||
|
self::validateDate($date);
|
||||||
|
}
|
||||||
$this->expirationDate = $date;
|
$this->expirationDate = $date;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,37 +114,71 @@ class BanEntry{
|
|||||||
return $str;
|
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
|
* @param string $str
|
||||||
*
|
*
|
||||||
* @return BanEntry|null
|
* @return BanEntry|null
|
||||||
|
* @throws \RuntimeException
|
||||||
*/
|
*/
|
||||||
public static function fromString(string $str){
|
public static function fromString(string $str) : ?BanEntry{
|
||||||
if(strlen($str) < 2){
|
if(strlen($str) < 2){
|
||||||
return null;
|
return null;
|
||||||
}else{
|
}else{
|
||||||
$str = explode("|", trim($str));
|
$str = explode("|", trim($str));
|
||||||
$entry = new BanEntry(trim(array_shift($str)));
|
$entry = new BanEntry(trim(array_shift($str)));
|
||||||
if(count($str) > 0){
|
do{
|
||||||
$datetime = \DateTime::createFromFormat(self::$format, array_shift($str));
|
if(empty($str)){
|
||||||
if(!($datetime instanceof \DateTime)){
|
break;
|
||||||
MainLogger::getLogger()->alert("Error parsing date for BanEntry for player \"" . $entry->getName() . "\", the format may be invalid!");
|
|
||||||
return $entry;
|
|
||||||
}
|
}
|
||||||
$entry->setCreated($datetime);
|
|
||||||
if(count($str) > 0){
|
$entry->setCreated(self::parseDate(array_shift($str)));
|
||||||
|
if(empty($str)){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
$entry->setSource(trim(array_shift($str)));
|
$entry->setSource(trim(array_shift($str)));
|
||||||
if(count($str) > 0){
|
if(empty($str)){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
$expire = trim(array_shift($str));
|
$expire = trim(array_shift($str));
|
||||||
if(strtolower($expire) !== "forever" and strlen($expire) > 0){
|
if(strtolower($expire) !== "forever" and strlen($expire) > 0){
|
||||||
$entry->setExpires(\DateTime::createFromFormat(self::$format, $expire));
|
$entry->setExpires(self::parseDate($expire));
|
||||||
}
|
}
|
||||||
if(count($str) > 0){
|
if(empty($str)){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
$entry->setReason(trim(array_shift($str)));
|
$entry->setReason(trim(array_shift($str)));
|
||||||
}
|
}while(false);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $entry;
|
return $entry;
|
||||||
}
|
}
|
||||||
|
@ -147,10 +147,16 @@ class BanList{
|
|||||||
if(is_resource($fp)){
|
if(is_resource($fp)){
|
||||||
while(($line = fgets($fp)) !== false){
|
while(($line = fgets($fp)) !== false){
|
||||||
if($line{0} !== "#"){
|
if($line{0} !== "#"){
|
||||||
|
try{
|
||||||
$entry = BanEntry::fromString($line);
|
$entry = BanEntry::fromString($line);
|
||||||
if($entry instanceof BanEntry){
|
if($entry instanceof BanEntry){
|
||||||
$this->list[$entry->getName()] = $entry;
|
$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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose($fp);
|
fclose($fp);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user