mirror of
https://github.com/PHPOffice/PhpSpreadsheet.git
synced 2026-09-04 22:50:27 +00:00
Recurse Directories Searching for Font File
Fix #2809. User felt font files should be searched recursively. The problem could be overcome merely by specifying a more precise font location. However, user has a point - the file layout on user's system is pretty common, and can be integrated into PhpSpreadsheet code easily. As a bonus, the DocBlock for setTrueTypeFontPath, which the user felt was misleading, doesn't even have to change.
This commit is contained in:
@@ -6,6 +6,8 @@ use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
|
||||
use PhpOffice\PhpSpreadsheet\RichText\RichText;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Alignment;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Font as FontStyle;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
|
||||
class Font
|
||||
{
|
||||
@@ -318,7 +320,8 @@ class Font
|
||||
|
||||
/**
|
||||
* Set the path to the folder containing .ttf files. There should be a trailing slash.
|
||||
* Typical locations on variout some platforms:
|
||||
* Path will be recursively searched for font file.
|
||||
* Typical locations on various platforms:
|
||||
* <ul>
|
||||
* <li>C:/Windows/Fonts/</li>
|
||||
* <li>/usr/share/fonts/truetype/</li>
|
||||
@@ -589,7 +592,7 @@ class Font
|
||||
}
|
||||
$fontFileAbsolute = preg_match('~^([A-Za-z]:)?[/\\\\]~', $fontFile) === 1;
|
||||
if (!$fontFileAbsolute) {
|
||||
$fontFile = self::$trueTypeFontPath . $separator . $fontFile;
|
||||
$fontFile = self::findFontFile(self::$trueTypeFontPath, $fontFile) ?? self::$trueTypeFontPath . $separator . $fontFile;
|
||||
}
|
||||
|
||||
// Check if file actually exists
|
||||
@@ -698,4 +701,36 @@ class Font
|
||||
|
||||
return $rowHeight;
|
||||
}
|
||||
|
||||
private static function findFontFile(string $startDirectory, string $desiredFont): ?string
|
||||
{
|
||||
$fontPath = null;
|
||||
if ($startDirectory === '') {
|
||||
return null;
|
||||
}
|
||||
if (file_exists("$startDirectory/$desiredFont")) {
|
||||
$fontPath = "$startDirectory/$desiredFont";
|
||||
} else {
|
||||
$it = new RecursiveDirectoryIterator(
|
||||
$startDirectory,
|
||||
RecursiveDirectoryIterator::SKIP_DOTS
|
||||
| RecursiveDirectoryIterator::FOLLOW_SYMLINKS
|
||||
);
|
||||
foreach (
|
||||
new RecursiveIteratorIterator(
|
||||
$it,
|
||||
RecursiveIteratorIterator::LEAVES_ONLY,
|
||||
RecursiveIteratorIterator::CHILD_FIRST
|
||||
) as $file
|
||||
) {
|
||||
if (basename($file) === $desiredFont) {
|
||||
$fontPath = $file;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $fontPath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ class FontFileNameTest extends TestCase
|
||||
{
|
||||
private const DEFAULT_DIRECTORY = 'tests/data/Shared/FakeFonts/Default';
|
||||
private const MAC_DIRECTORY = 'tests/data/Shared/FakeFonts/Mac';
|
||||
private const RECURSE_DIRECTORY = 'tests/data/Shared/FakeFonts/Recurse';
|
||||
|
||||
private string $holdDirectory;
|
||||
|
||||
@@ -182,4 +183,29 @@ class FontFileNameTest extends TestCase
|
||||
'non-absolute path uses TrueTypeFontPath' => ['cour.ttf', ['name' => 'Courier New']],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerRecurse
|
||||
*/
|
||||
public function testRecurseFilenames(string $expected, array $fontArray): void
|
||||
{
|
||||
if ($expected === 'exception') {
|
||||
$this->expectException(SSException::class);
|
||||
$this->expectExceptionMessage('TrueType Font file not found');
|
||||
}
|
||||
Font::setTrueTypeFontPath(self::RECURSE_DIRECTORY);
|
||||
$font = (new StyleFont())->applyFromArray($fontArray);
|
||||
$result = Font::getTrueTypeFontFileFromFont($font);
|
||||
self::assertSame($expected, basename($result));
|
||||
}
|
||||
|
||||
public static function providerRecurse(): array
|
||||
{
|
||||
return [
|
||||
'in subdirectory' => ['arial.ttf', ['name' => 'Arial']],
|
||||
'in subdirectory bold' => ['arialbd.ttf', ['name' => 'Arial', 'bold' => true]],
|
||||
'in main directory' => ['cour.ttf', ['name' => 'Courier New']],
|
||||
'not in main or subdirectory' => ['exception', ['name' => 'Courier New', 'bold' => true]],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user