PHP生成iCal文件时,如何避免特定字段的空格被移除?
解决PHP生成iCal时字段空格被误删的问题
问题描述
我尝试用PHP构建iCal订阅源,参考教程写了代码,目前整体输出正常,但为了让输出符合验证要求,在函数末尾用str_replace(' ', '', $icalObject)移除了所有空格,这会同时删除$event->summary和$event->location中的空格,导致这些字段内容失效。请问有没有办法避免这些字段的空格被移除?
原代码如下:
public function getEventsICalObject() { $events = TechEvents::all(); define('ICAL_FORMAT', 'Ymd\THis\Z'); $icalObject = "BEGIN:VCALENDAR VERSION:2.0 METHOD:PUBLISH PRODID:-//Testing Calendar//Tech Events//EN "; // loop over events foreach ($events as $event) { $icalObject .= "BEGIN:VEVENT DTSTART:" . date(ICAL_FORMAT, strtotime($event->starts)) . " DTEND:" . date(ICAL_FORMAT, strtotime($event->ends)) . " DTSTAMP:" . date(ICAL_FORMAT, strtotime($event->created_at)) . " SUMMARY:$event->summary UID:$event->uid STATUS:" . strtoupper($event->status) . " LAST-MODIFIED:" . date(ICAL_FORMAT, strtotime($event->updated_at)) . " LOCATION:$event->location END:VEVENT "; } // close calendar $icalObject .= "END:VCALENDAR"; // Set the headers header('Content-type: text/calendar; charset=utf-8'); header('Content-Disposition: attachment; filename="cal.ics"'); $icalObject = str_replace(' ', '', $icalObject); echo $icalObject; }
解决方案
方案1:从根源避免多余空格(最优解)
问题本质是生成iCal内容时,每行开头加了多余的缩进空格,后期不得不全局删除。直接去掉字符串里的缩进空格,就能不用全局替换,同时保留字段内容里的空格。
修改后的代码:
public function getEventsICalObject() { $events = TechEvents::all(); define('ICAL_FORMAT', 'Ymd\THis\Z'); // 去掉每行开头的缩进空格 $icalObject = "BEGIN:VCALENDAR VERSION:2.0 METHOD:PUBLISH PRODID:-//Testing Calendar//Tech Events//EN "; foreach ($events as $event) { // 同样去掉VEVENT块里每行的缩进空格 $icalObject .= "BEGIN:VEVENT DTSTART:" . date(ICAL_FORMAT, strtotime($event->starts)) . " DTEND:" . date(ICAL_FORMAT, strtotime($event->ends)) . " DTSTAMP:" . date(ICAL_FORMAT, strtotime($event->created_at)) . " SUMMARY:" . $this->escapeIcalText($event->summary) . " UID:" . $event->uid . " STATUS:" . strtoupper($event->status) . " LAST-MODIFIED:" . date(ICAL_FORMAT, strtotime($event->updated_at)) . " LOCATION:" . $this->escapeIcalText($event->location) . " END:VEVENT "; } $icalObject .= "END:VCALENDAR"; header('Content-type: text/calendar; charset=utf-8'); header('Content-Disposition: attachment; filename="cal.ics"'); // 移除全局替换空格的代码 echo $icalObject; } // 新增iCal文本转义函数,处理特殊字符(可选但推荐) private function escapeIcalText($text) { $text = str_replace('\\', '\\\\', $text); $text = str_replace(',', '\\,', $text); $text = str_replace(';', '\\;', $text); $text = str_replace("\n", "\\n", $text); return $text; }
方案2:用正则仅删除行首空格
如果不想修改原字符串的缩进格式,可以用正则表达式只删除每行开头的空格,不影响字段内容里的空格:
把全局替换的代码替换成:
// 仅删除每行开头的空白字符(空格、制表符等) $icalObject = preg_replace('/^\s+/m', '', $icalObject);
解释:/^\s+/m中,^匹配行开头,\s+匹配一个或多个空白字符,m修饰符让^作用于每一行,而非整个字符串开头。
方案3:先保护字段内容再替换(不推荐)
可以先把字段内容里的空格替换成临时标记,替换完行首空格后再恢复,但这种方法容易出错,不如前两种方案可靠:
// 先替换字段内容里的空格为临时标记 foreach ($events as $event) { $summary = str_replace(' ', '[[SPACE]]', $event->summary); $location = str_replace(' ', '[[SPACE]]', $event->location); $icalObject .= "BEGIN:VEVENT DTSTART:" . date(ICAL_FORMAT, strtotime($event->starts)) . " ... SUMMARY:$summary ... LOCATION:$location END:VEVENT "; } // 全局删除所有空格 $icalObject = str_replace(' ', '', $icalObject); // 恢复字段里的空格 $icalObject = str_replace('[[SPACE]]', ' ', $icalObject);
内容的提问来源于stack exchange,提问作者BigJobbies
相关产品推荐
相关产品推荐

