Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recurse Directories Searching for Font File #3830

Merged
merged 5 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,12 @@ and this project adheres to [Semantic Versioning](https://semver.org).
- Html omitting some charts. [Issue #3767](https://github.com/PHPOffice/PhpSpreadsheet/issues/3767) [PR #3771](https://github.com/PHPOffice/PhpSpreadsheet/pull/3771)
- Case Insensitive Comparison for Sheet Names [PR #3791](https://github.com/PHPOffice/PhpSpreadsheet/pull/3791)
- Performance improvement for Xlsx Reader. [Issue #3683](https://github.com/PHPOffice/PhpSpreadsheet/issues/3683) [PR #3810](https://github.com/PHPOffice/PhpSpreadsheet/pull/3810)
- Strip `xlfn.` and `xlws.` from Formula Translations. [Issue #3819](https://github.com/PHPOffice/PhpSpreadsheet/issues/3819) [PR #3828](https://github.com/PHPOffice/PhpSpreadsheet/pull/3828)
- Prevent loop in Shared/File. [Issue #3807](https://github.com/PHPOffice/PhpSpreadsheet/issues/3807) [PR #3809](https://github.com/PHPOffice/PhpSpreadsheet/pull/3809)
- Consistent handling of decimal/thousands separators between StringHelper and Php setlocale. [Issue #3811](https://github.com/PHPOffice/PhpSpreadsheet/issues/3811) [PR #3815](https://github.com/PHPOffice/PhpSpreadsheet/pull/3815)
- Clone worksheet with tables or charts. [Issue #3820](https://github.com/PHPOffice/PhpSpreadsheet/issues/3820) [PR #3821](https://github.com/PHPOffice/PhpSpreadsheet/pull/3821)
- COUNTIFS Does Not Require xlfn. [Issue #3819](https://github.com/PHPOffice/PhpSpreadsheet/issues/3819) [PR #3827](https://github.com/PHPOffice/PhpSpreadsheet/pull/3827)
- Strip `xlfn.` and `xlws.` from Formula Translations. [Issue #3819](https://github.com/PHPOffice/PhpSpreadsheet/issues/3819) [PR #3828](https://github.com/PHPOffice/PhpSpreadsheet/pull/3828)
- Recurse directories searching for font file. [Issue #2809](https://github.com/PHPOffice/PhpSpreadsheet/issues/2809) [PR #3830](https://github.com/PHPOffice/PhpSpreadsheet/pull/3830)

## 1.29.0 - 2023-06-15

Expand Down
43 changes: 40 additions & 3 deletions src/PhpSpreadsheet/Shared/Font.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Font as FontStyle;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;

class Font
{
Expand Down Expand Up @@ -203,15 +205,17 @@ class Font
/**
* Array that can be used to supplement FONT_FILE_NAMES for calculating exact width.
*
* @var array
* @var array<string, array<string, string>>
*/
private static $extraFontArray = [];

/** @param array<string, array<string, string>> $extraFontArray */
public static function setExtraFontArray(array $extraFontArray): void
{
self::$extraFontArray = $extraFontArray;
}

/** @return array<string, array<string, string>> */
public static function getExtraFontArray(): array
{
return self::$extraFontArray;
Expand Down Expand Up @@ -318,7 +322,8 @@ public static function getAutoSizeMethod()

/**
* 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>
Expand Down Expand Up @@ -589,7 +594,7 @@ public static function getTrueTypeFontFileFromFont(FontStyle $font, bool $checkP
}
$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
Expand Down Expand Up @@ -698,4 +703,36 @@ public static function getDefaultRowHeightByFont(FontStyle $font): float

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::CATCH_GET_CHILD
) as $file
) {
if (basename($file) === $desiredFont) {
$fontPath = $file;

break;
}
}
}

return $fontPath;
}
}
26 changes: 26 additions & 0 deletions tests/PhpSpreadsheetTests/Shared/FontFileNameTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -182,4 +183,29 @@ public static function providerOverrideAbsolute(): array
'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]],
];
}
}
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.