Fonts 如何在我自己的服务器上托管google web字体?

Fonts 如何在我自己的服务器上托管google web字体?,fonts,google-font-api,Fonts,Google Font Api,我需要在内部网应用程序上使用一些谷歌字体。客户端可能有也可能没有internet连接。阅读许可条款,似乎它是合法允许的。只要您遵守字体许可条款(通常是OFL),它就是合法允许的 您将需要一组web字体格式,并且可以生成这些格式 但是OFL要求字体在被修改时被重命名,使用生成器意味着修改字体 请记住我的答案已经过时了 下面还有其他技术上更复杂的答案,例如: 因此,不要因为这是目前公认的答案而给人留下这样的印象:这仍然是最好的答案 您现在还可以通过github上的存储库下载google的

我需要在内部网应用程序上使用一些谷歌字体。客户端可能有也可能没有internet连接。阅读许可条款,似乎它是合法允许的。

只要您遵守字体许可条款(通常是OFL),它就是合法允许的

您将需要一组web字体格式,并且可以生成这些格式


但是OFL要求字体在被修改时被重命名,使用生成器意味着修改字体

请记住我的答案已经过时了

下面还有其他技术上更复杂的答案,例如:

因此,不要因为这是目前公认的答案而给人留下这样的印象:这仍然是最好的答案


您现在还可以通过github上的存储库下载google的整个字体集。它们还提供了一个新的解决方案


您首先将字体选择下载为压缩包,为您提供一组真正的字体。将它们复制到公共的地方,可以从css链接到的地方

在google webfont下载页面上,您会发现一个包含链接,如下所示:

http://fonts.googleapis.com/css?family=Cantarell:400,700,400italic,700italic|Candal
它通过一组
@font-face
定义链接到定义字体的CSS

在浏览器中打开它,将它们复制并粘贴到您自己的CSS中,并修改URL以包含正确的字体文件和格式类型

因此:

@font-face{
字体系列:“Cantarell”;
字体风格:普通;
字号:700;
src:local('Cantarell-Bold')、local('Cantarell-Bold')、url(http://themes.googleusercontent.com/static/fonts/cantarell/v3/Yir4ZDsCn4g1kWopdg-ehHhCUOGz7vYGh680lGh-uXM.woff)格式(“woff”);
}
变成这样:

/*您的本地CSS文件*/
@字体{
字体系列:“Cantarell”;
字体风格:普通;
字号:700;
src:local('Cantarell-Bold')、local('Cantarell-Bold')、url(../font/Cantarell-Bold.ttf)格式('truetype');
}
正如您所见,在您自己的系统上以这种方式托管字体的一个缺点是,您将自己限制为真正的类型格式,而google webfont服务由访问设备决定将传输哪些格式

此外,我还必须将
.htaccess
文件添加到包含mime类型字体的目录中,以避免在Chrome开发工具中出现错误

对于这个解决方案,只需要真正的类型,但是如果您还想包括不同的字体,比如
font-awesome
,那么定义更多字体并没有什么坏处

#.htaccess
AddType application/vnd.ms-fontobject .eot
AddType font/ttf .ttf
AddType font/otf .otf
AddType application/x-font-woff .woff

CSS文件的内容(来自包含URL)取决于我从哪个浏览器查看它。例如,当浏览到使用Chrome时,该文件仅包含WOFF链接。使用Internet Explorer(如下),它包括EOT和WOFF。我将所有链接粘贴到浏览器中以下载它们

@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400;
  src: url(http://themes.googleusercontent.com/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3fY6323mHUZFJMgTvxaG2iE.eot);
  src: local('Open Sans'), local('OpenSans'), url(http://themes.googleusercontent.com/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3fY6323mHUZFJMgTvxaG2iE.eot) format('embedded-opentype'), url(http://themes.googleusercontent.com/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3T8E0i7KZn-EPnyo3HZu7kw.woff) format('woff');
}
当您托管自己的web字体时,您需要处理遗留的浏览器错误等。当您使用Google web字体(由Google托管)时,Google会自动链接到该浏览器的正确字体类型。

我写了一篇文章,用不同的用户代理在Google的服务器上获取CSS文件,将不同的字体格式下载到本地目录,并写入包含它们的CSS文件。请注意,该脚本需要Bash版本4.x

有关脚本,请参见(我不在这里复制它,所以我只需要在需要时在一个地方更新它)


编辑:移动到我有一个用PHP编写的脚本,类似于从Google自动下载CSS和字体(提示和未编辑的)。然后,它根据用户代理从您自己的服务器提供正确的CSS和字体。它保留自己的缓存,因此用户代理的字体和CSS只需下载一次

它还处于初级阶段,但可以在这里找到:

有一个工具可以帮助您下载所有字体变体。它还生成相应的CSS以供实现。不赞成

localfont已关闭。相反,您可以使用


最好的解决方案是

它允许您选择多个字体变体,这节省了大量时间。

我在grunt任务中使用过

module.exports = function(grunt) {

    grunt.initConfig({
       pkg: grunt.file.readJSON('package.json'),

        "local-googlefont" : {
            "opensans" : {
                "options" : {
                    "family" : "Open Sans",
                    "sizes" : [
                        300,
                        400,
                        600
                    ],
                    "userAgents" : [
                        "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0)",  //download eot
                        "Mozilla/5.0 (Linux; U; Android 4.1.2; nl-nl; GT-I9300 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", //download ttf
                        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1944.0 Safari/537.36" //download woff and woff2
                    ],
                    "cssDestination" : "build/fonts/css",
                    "fontDestination" : "build/fonts",
                    "styleSheetExtension" : "css",
                    "fontDestinationCssPrefix" : "fonts"

                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-local-googlefont');
 };
然后,要检索它们:

grunt local-googlefont:opensans

注意,我使用的是原版的fork,在检索名称中带有空格的字体时效果更好。

实际上,您可以直接从Google下载所有字体格式变体,并将其包含在css中,以便从服务器上提供服务。这样你就不用担心谷歌跟踪你网站的用户。然而,不利的一面可能会减慢你自己的发球速度。字体对资源要求很高。我还没有在这个问题上做过任何测试,不知道是否有人有类似的想法。

我的解决方案是从google web fonts下载TTF文件,然后使用。

除了我想建议的之外。它也是一个bash(v4)脚本,使web服务器操作员能够从自己的web服务器下载并提供googleweb字体。但除了另一个bash脚本外,它还允许用户完全自动化(通过cron等)提供最新的字体文件和css文件。

我制作了一个小PHP脚本,从Google字体css导入URL获取下载链接,如:

您可以在此处使用此工具:

例如,如果您使用上述导入URL,您将得到以下结果:


当您想在自己的服务器上托管所有字体(或其中一些字体)时,您可以从该repo下载字体,并按照您想要的方式使用:

如果您只是想这样做来解决Google字体附带的利用浏览器缓存问题,您可以使用替代字体,并包括以下字体:

<link href="https://pagecdn.io/lib/easyfonts/fonts.css" rel="stylesheet" />

或特定字体,如:

<link href="https://pagecdn.io/lib/easyfonts/lato.css" rel="stylesheet" />

有一个非常简单的脚本,用纯Java编写,可以从Google Web字体链接下载所有字体(支持多种字体)。它还下载CSS文件和
npm install typeface-roboto --save
import 'typeface-roboto'
$obj = new GoogleFontsDownloader;
        
if(isset($_GET['url']) && !empty($_GET['url']))
{
    $obj->generate($_GET['url']);
}

if(isset($_GET['download']) && !empty($_GET['download']) && $_GET['download']=='true')
{
    $obj->download();
}
/**
* GoogleFontsDownloader
* Easy way to download any google fonts.
* @author     Shohrab Hossain
* @version    1.0.0 
*/
class GoogleFontsDownloader
{
    private $url      = '';
    private $dir      = 'dist/';
    private $fontsDir = 'fonts/';
    private $cssDir   = 'css/';
    private $fileName = 'fonts.css';
    private $content  = '';
    private $errors   = '';
    private $success  = '';
    public  $is_downloadable  = false;

    public function __construct()
    {
        ini_set('allow_url_fopen', 'on');
        ini_set('allow_url_include', 'on');
    }
 
    public function generate($url = null)
    {
        if (filter_var($url, FILTER_VALIDATE_URL) === FALSE) 
        {
            $this->errors .= "<li><strong>Invalid url!</strong> $url</li>";
        }
        else
        {
            $this->url = $url;
            // delete previous files
            $this->_destroy();
            // write font.css
            $this->_css();
            // write fonts
            $this->_fonts();
            // archive files
            $this->_archive();
        }  
        // show all messages
        $this->_message();
    }
 
    public function download()
    { 
        // Download the created zip file
        $zipFileName = trim($this->dir, '/').'.zip';
        if (file_exists($zipFileName))
        {
            header("Content-type: application/zip");
            header("Content-Disposition: attachment; filename = $zipFileName");
            header("Pragma: no-cache");
            header("Expires: 0");
            readfile("$zipFileName");
 
            // delete file 
            unlink($zipFileName);
            array_map('unlink', glob("$this->dir/*.*"));
            rmdir($this->dir);

        } 
    }   
 
    private function _archive()
    {
        if (is_dir($this->dir))
        {
            $zipFileName = trim($this->dir, '/').'.zip';
            $zip = new \ZipArchive(); 
            if ($zip->open($zipFileName, ZipArchive::CREATE) === TRUE) 
            {
                $zip->addGlob($this->dir. "*.*");
                $zip->addGlob($this->dir. "*/*.*");
                if ($zip->status == ZIPARCHIVE::ER_OK)
                {
                    $this->success .= '<li>Zip create successful!</li>';
                    $this->is_downloadable = true;
                }
                else 
                {
                    $this->errors .= '<li>Failed to create to zip</li>';
                } 
            } 
            else 
            {
                $this->errors .= '<li>ZipArchive not found!</li>';
            }  
            $zip->close(); 
        }
        else
        {
            $this->errors .= "<li><strong>File</strong> not exists!</li>";
        } 
    }   
  
    private function _css()
    {  
        $filePath = $this->dir.$this->cssDir.$this->fileName;
        $content  = $this->_request($this->url);
        if (!empty($content))
        {
            if (file_put_contents($filePath, $content))
            {
                $this->success .= "<li>$this->fileName generated successful!</li>";
                $this->content = $content; 
            }
            else
            {
                $this->errors .= '<li>Permission errro in $this->fileName! Unable to write $filePath.</li>';
            }
        }
        else
        {
            $this->errors .= '<li>Unable to create fonts.css file!</li>';
        }
    }

    private function _fonts()
    {
        if (!empty($this->content))
        {
            preg_match_all('#\bhttps?://[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/))#', $this->content, $match);
            $gFontPaths = $match[0];
            if (!empty($gFontPaths) && is_array($gFontPaths) && sizeof($gFontPaths)>0)
            {
                $count = 0;
                foreach ($gFontPaths as $url) 
                {
                    $name     = basename($url);
                    $filePath = $this->dir.$this->fontsDir.$name;
                    $this->content = str_replace($url, '../'.$this->fontsDir.$name, $this->content);

                    $fontContent  = $this->_request($url);
                    if (!empty($fontContent))
                    {
                        file_put_contents($filePath, $fontContent);
                        $count++;
                        $this->success .= "<li>The font $name downloaded!</li>";
                    }
                    else
                    {
                        $this->errors .= "<li>Unable to download the font $name!</li>";
                    } 
                }

                file_put_contents($this->dir.$this->cssDir.$this->fileName, $this->content);
                $this->success .= "<li>Total $count font(s) downloaded!</li>";
            }
        }
    }

    private function _request($url)
    {
        $ch = curl_init(); 
        curl_setopt_array($ch, array(
            CURLOPT_SSL_VERIFYPEER => FALSE,
            CURLOPT_HEADER         => FALSE,
            CURLOPT_FOLLOWLOCATION => TRUE,
            CURLOPT_URL            => $url,
            CURLOPT_REFERER        => $url,
            CURLOPT_RETURNTRANSFER => TRUE,
        ));
        $result = curl_exec($ch);
        curl_close($ch);

        if (!empty($result))
        {
            return $result;
        } 
        return false;
    }

    private function _destroy()
    {
        $cssPath = $this->dir.$this->cssDir.$this->fileName;
        if (file_exists($cssPath) && is_file($cssPath))
        {
            unlink($cssPath);
        } 
        else
        {
            mkdir($this->dir.$this->cssDir, 0777, true);
        }

        $fontsPath = $this->dir.$this->fontsDir;
        if (!is_dir($fontsPath))
        {
            mkdir($fontsPath, 0777, true);
        }
        else
        {
            array_map(function($font) use($fontsPath) {
                if (file_exists($fontsPath.$font) && is_file($fontsPath.$font))
                {
                    unlink($fontsPath.$font);
                }
            }, glob($fontsPath.'*.*')); 
        }
    }

    private function _message()
    {
        if (strlen($this->errors)>0)
        {
            echo "<div class='alert alert-danger'><ul>$this->errors</ul></div>";
        }  
        if (strlen($this->success)>0)
        {
            echo "<div class='alert alert-success'><ul>$this->success</ul></div>";
        } 
    } 
}