如何使用 PHP GD 和 TwitterOAuth 动态更新 Twitter 封面图片以显示最新关注者

2025-06-05

如何使用 PHP GD 和 TwitterOAuth 动态更新 Twitter 封面图片以显示最新关注者

一周前,我看到了一条令我非常好奇的推文:

这让我想起职业生涯中其他几次兴奋不已,甚至近乎痴迷地想要弄清楚某样东西是如何制作的。第一次(很久以前)是看到一个“杂志封面工具”,只需上传一张照片即可生成杂志封面。这让我开启了一个全新的探索世界,也让我完成了第一个成功的项目,让我辞去了当时的工作,靠谷歌广告收入生活。没错,那是一个用PHP和GD语言制作的在线杂志封面生成器 :)

另一个让我同样渴望了解他们是如何做到的,是我发现了这个工具,可以追踪哪些人在 Twitter 上取消了关注。这又一次让我进入了一个充满发现、开源贡献和 Twitter API 深度挖掘的世界。

所以当我看到Tony的推文时,我意识到这基本上就是封面生成器 + Twitter API 的结合。我非常兴奋地想要实现它!花了大约一周时间,每天几个小时,因为我有一些可以重复使用和重新利用的小代码块。

这是最终结果,您也可以现场查看

Twitter 标题图片,包含最近的关注者和特色 GitHub 赞助商

这个小项目让我兴奋的是,它的可能性是无限的。你可以展示任何你想要的内容,只要它有动态输出,并且可以通过编程方式获取(比如通过 API)。同样的方法也可以用来修改你的个人资料图片。

在本教程中,我们将构建一个更简单的动态标题版本,用于显示你最新的 5 位 Twitter 关注者。dynacover GitHub仓库包含一些其他模板,你稍后可以尝试一下。

好了,闲话少叙,我们开始行动吧!

开始之前

在继续之前,请确保您已准备好以下内容:

  • 在dev.twitter.com上注册的具有读写权限的应用程序
  • 从应用程序设置页面获取以下4个令牌:
    • 消费者/API 令牌(应用程序令牌)
    • 消费者/API 秘密(应用程序秘密)
    • 访问密钥(用户令牌)
    • 访问秘密(用户秘密)
  • 命令行中可运行的 PHP 开发环境,安装了以下依赖项:
    • php-cli7.4+
    • ext-gd
    • ext-json
    • ext-curl
    • 作曲家
    • 一张用作封面的 PNG 图片,将粘贴在所有图层的顶部。图片尺寸必须为 1500x500,并包含用于放置头像图片的透明占位符,例如这张,您可以自由使用和修改。如果您创建了包含不同位置占位符的自定义横幅,则还需要每个占位符的大小和坐标。

我们鼓励您使用源代码编辑器(例如Visual Studio Code)来促进 PHP 项目内的工作。

在本演示中,我们将使用Minicli(一个极简的 PHP 命令行应用程序框架)创建一个命令行应用程序。我们将使用TwitterOAuth库与 Twitter API 进行通信。

如果您希望使用现有存储库中的代码,或者只是想尝试一下这个演示,您可以查看GitHub 上的erikaheidi/dynacover。为了匹配本指南中的代码,请下载0.1 版本,因为main分支会随着时间而变化。

1. 引导应用程序

首先使用Minicli启动一个小型命令行应用程序。这里我们将其命名为dynacover

composer create-project --prefer-dist minicli/application dynacover
Enter fullscreen mode Exit fullscreen mode
Creating a "minicli/application" project at "./dynacover"
Installing minicli/application (2.0.1)
  - Installing minicli/application (2.0.1): Extracting archive
Created project in /home/erika/Projects/dynacover
Loading composer repositories with package information
Updating dependencies
Lock file operations: 1 install, 0 updates, 0 removals
  - Locking minicli/minicli (2.2.1)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing minicli/minicli (2.2.1): Extracting archive
Generating autoload files
1 package you are using is looking for funding.
Use the `composer fund` command to find out more!

Enter fullscreen mode Exit fullscreen mode

这将引导应用程序。进入新目录并查看文件。以下是新 Minicli 应用程序中目录结构的简要概述:

cd dynacover
Enter fullscreen mode Exit fullscreen mode
.
├── app
│   └── Command
├── composer.json
├── composer.lock
├── LICENSE
├── minicli
├── README.md
└── vendor
    ├── autoload.php
    ├── composer
    └── minicli
Enter fullscreen mode Exit fullscreen mode

app/Command目录是所有命令的定义位置。我们将在下一步中处理这个问题。

接下来,abraham/twitteroauth通过 Composer 将其作为依赖项包含进来:

composer require abraham/twitteroauth
Enter fullscreen mode Exit fullscreen mode

您还可以重命名脚本以匹配应用程序名称:

mv minicli dynacover
Enter fullscreen mode Exit fullscreen mode

要测试一切是否按预期工作,请运行:

php dynacover help
Enter fullscreen mode Exit fullscreen mode

您应该看到以下输出:

Available Commands

help
└──table
└──test

Enter fullscreen mode Exit fullscreen mode

这些命令已在目录中实现,app/Command/Help/作为示例命令,您可以参考一下。下一步,我们将开始创建新命令。

2. 使用 TwitterOAuth 库获取新关注者

在编写动态生成图像的代码之前,首先确保您可以使用 TwitterOAuth 库和您的应用程序/用户密钥获取您的最新关注者。

我们将创建一个简单的命令来列出您的最新关注者。

首先,我们需要设置 Twitter 令牌,以便您可以从命令控制器获取它们。最简单的方法是创建一个包含凭证的单独文件,并将其导入到应用程序的配置中。.gitignore如果您使用版本控制,还应确保此文件包含在您的配置文件中,以免它与应用程序代码一起提交。

安全存储 Twitter 凭证

在应用程序文件夹的根目录中创建一个名为 的新文件credentials.php。该文件应返回一个包含应用程序敏感数据的数组。

将以下内容复制到您的credentials.php文件中,并用您自己的 Twitter 凭据替换所有密钥:

#credentials.php
<?php

return [
    'twitter_consumer_key' => 'APP_CONSUMER_KEY',
    'twitter_consumer_secret' => 'APP_CONSUMER_SECRET',
    'twitter_user_token' => 'USER_ACCESS_TOKEN',
    'twitter_token_secret' => 'USER_ACCESS_TOKEN_SECRET',
];
Enter fullscreen mode Exit fullscreen mode

为了确保此文件不包含在版本控制中,你应该在.gitignore文件中添加一行。你可以使用以下命令执行此操作,该命令会将新行添加到该文件:

echo "credentials.php" >> .gitignore
Enter fullscreen mode Exit fullscreen mode

然后,编辑dynacover脚本将这些数据合并到主配置中。操作如下:

#dynacover
#!/usr/bin/php
<?php

if (php_sapi_name() !== 'cli') {
    exit;
}

require __DIR__ . '/vendor/autoload.php';

use Minicli\App;

$config = [
    'app_path' => __DIR__ . '/app/Command'
];

if (is_file(__DIR__ . '/credentials.php')) {
    $config = array_merge($config, include __DIR__ . '/credentials.php');
}

$app = new App($config);

$app->runCommand($argv);

Enter fullscreen mode Exit fullscreen mode

现在您应该能够从任何命令控制器获取这些凭据。

创建新命令来获取关注者

有了凭证后,您就可以开始使用 Twitter API 了。在其中创建一个app/Command名为 的新目录Fetch

mkdir app/Command/Fetch
Enter fullscreen mode Exit fullscreen mode

使用您首选的代码编辑器在 创建一个新文件app/Command/Fetch/FollowersController.php。这是一个需要从 扩展的类,Minicli\Command\CommandController并实现一个名为 的方法handle,该方法将在从提示符调用命令时处理该命令。

从该handle方法中,您将从对象中获取所需的凭据$this->getApp()->config,可以作为魔术属性访问:

$api_token = $this->getApp()->config->twitter_consumer_key;
$api_secret = $this->getApp()->config->twitter_consumer_secret;
$access_token = $this->getApp()->config->twitter_user_token;
$token_secret = $this->getApp()->config->twitter_token_secret;
Enter fullscreen mode Exit fullscreen mode

然后,使用该TwitterOAuth库,您可以创建一个请求来获取您的最新关注者

$client = new TwitterOAuth($api_token, $api_secret, $access_token, $token_secret);
$followers = $client->get('/followers/list', [
    'skip_status' => true,
    'count' => 10
]);
Enter fullscreen mode Exit fullscreen mode

以下代码包含完整的实现,并在最后列出了结果作为输出:

#app/Command/Fetch/FollowersController.php
<?php

namespace App\Command\Fetch;

use Minicli\Command\CommandController;
use Abraham\TwitterOAuth\TwitterOAuth;

class FollowersController extends CommandController
{
    public function handle()
    {
        $api_token = $this->getApp()->config->twitter_consumer_key;
        $api_secret = $this->getApp()->config->twitter_consumer_secret;
        $access_token = $this->getApp()->config->twitter_user_token;
        $token_secret = $this->getApp()->config->twitter_token_secret;

        $client = new TwitterOAuth($api_token, $api_secret, $access_token, $token_secret);
        $followers = $client->get('/followers/list', [
            'skip_status' => true,
            'count' => 10
        ]);

        $this->getPrinter()->info("Latest Followers", true);

        foreach ($followers->users as $follower) {
            $this->getPrinter()->info($follower->screen_name);
        }

        $this->getPrinter()->info("Finished.");
        return 0;
    }
}
Enter fullscreen mode Exit fullscreen mode

您现在可以用以下命令运行此命令:

php dynacover fetch followers
Enter fullscreen mode Exit fullscreen mode

如果一切按预期进行,您应该会看到一个包含最近 10 位新关注者的列表,如下所示:

屏幕截图终端列表最近的关注者

有了这些数据,我们就可以开始构建动态封面图像。

3. 生成带有用户头像的封面

现在,您将构建一个新命令来生成封面图片。我们需要一张基础图片,将其粘贴在头像图片之上,以获得最佳效果。我使用Canva创建了封面图片,但您可以使用任何能够处理 PNG 格式和透明度的图像/照片编辑器。

在本演示中,我们将使用此示例图片。在 Canva 上创建此图片后,我在 Gimp 上打开了它,并使用圆形选择工具选择要放置个人资料图片的位置,然后点击“删除”按钮删除图片的该部分并使其透明:

在 Gimp 上创建透明占位符

我们的坐标将基于该图像。

设置示例封面图片

app在目录中创建一个名为的新文件夹Resources来放置此封面图像。

mkdir app/Resources
cp ~/Downloads/cover_basic.png app/Resources/twitter_cover.png
Enter fullscreen mode Exit fullscreen mode

创建封面生成命令

mkdir app/Command/Cover
Enter fullscreen mode Exit fullscreen mode

在该文件夹中创建一个名为 的新命令控制器GenerateController,以便稍后可以访问它dynacover cover generate。您可以将以下引导代码放入其中:

<?php

namespace App\Command\Cover;

use Minicli\Command\CommandController;

class GenerateController extends CommandController
{
    public function handle()
    {
        // TODO: Implement handle() method.
    }
}
Enter fullscreen mode Exit fullscreen mode

以下是我们现在需要做的事情:

1) 获取最新关注者(5);
3) 将他们的头像下载到临时位置;
4) 使用创建一个新的 GD 图像资源imagecreatetruecolor,尺寸为 1500x500;
5) 循环遍历具有正确坐标的数组以粘贴头像图像,并使用imagecopyresampled将这些图像放置在空白的 GD 资源中;
6) 最后将 PNG 图像放在顶部;
7) 将图像写入固定位置,以便我们稍后将其上传到 Twitter。

如果你想挑战一下,自己动手实现一下,那就来吧!我鼓励你尝试一下。如果你只是想看看它能不能运行,可以将下面的控制器代码复制到你自己的GenerateController.php文件中。

#app/Command/Cover/GenerateController.php
<?php

namespace App\Command\Cover;

use Abraham\TwitterOAuth\TwitterOAuth;
use Minicli\Command\CommandController;

class GenerateController extends CommandController
{
    public function handle()
    {
        $api_token = $this->getApp()->config->twitter_consumer_key;
        $api_secret = $this->getApp()->config->twitter_consumer_secret;
        $access_token = $this->getApp()->config->twitter_user_token;
        $token_secret = $this->getApp()->config->twitter_token_secret;

        $client = new TwitterOAuth($api_token, $api_secret, $access_token, $token_secret);
        $followers = $client->get('/followers/list', [
            'skip_status' => true,
            'count' => 5
        ]);

        if (!isset($followers->users)) {
            $this->getPrinter()->error("An error occurred.");
            return 1;
        }

        $users = $followers->users;
        $placeholders = $this->getPlaceholders();

        $cover_final = imagecreatetruecolor(1500, 500);

        foreach ($placeholders as $key => $placeholder) {
            $follower = $users[$key];
            $this->getPrinter()->info("Adding user to banner: $follower->screen_name");

            $path = $this->downloadAvatar($follower->profile_image_url);
            $resource = $this->getResource($path);
            $info = getimagesize($path);

            if ($resource) {
                imagecopyresampled(
                    $cover_final,
                    $resource,
                    $placeholder['pos_x'],
                    $placeholder['pos_y'],
                    0,
                    0,
                    $placeholder['width'],
                    $placeholder['height'],
                    $info[0],
                    $info[1]
                );
            }
        }

        //now finish with the cover image on top
        $cover = imagecreatefrompng(__DIR__ . '/../../Resources/cover_template.png');

        if ($cover) {
            imagecopyresized(
                $cover_final,
                $cover,
                0,
                0,
                0,
                0,
                1500,
                500,
                1500,
                500
            );
        }

        $save_path = __DIR__ . '/../../../latest_header.png';
        imagepng($cover_final, $save_path);
        $this->getPrinter()->info("Finished generating cover at $save_path.");

        return 0;
    }

    public function getPlaceholders(): array
    {
        return [
            [
                'pos_x' => 486,
                'pos_y' => 272,
                'width' => 130,
                'height' => 130
            ],[
                'pos_x' => 670,
                'pos_y' => 272,
                'width' => 130,
                'height' => 130
            ],[
                'pos_x' => 859,
                'pos_y' => 272,
                'width' => 130,
                'height' => 130
            ],[
                'pos_x' => 1049,
                'pos_y' => 272,
                'width' => 130,
                'height' => 130
            ],[
                'pos_x' => 1236,
                'pos_y' => 272,
                'width' => 130,
                'height' => 130
            ]
        ];
    }

    public function getResource($path)
    {
        $info = getimagesize($path);
        $extension = image_type_to_extension($info[2]);

        if (strtolower($extension) == '.png') {
            return imagecreatefrompng($path);
        }

        if (strtolower($extension) == '.jpeg' OR strtolower($extension) == '.jpg') {
            return imagecreatefromjpeg($path);
        }

        return null;
    }

    public function downloadAvatar($url): string
    {
        $file_contents = file_get_contents($url);

        $file_path = "/tmp/" . basename($url);

        $image = fopen($file_path, "w+");
        fwrite($image, $file_contents);
        fclose($image);

        return $file_path;
    }
}
Enter fullscreen mode Exit fullscreen mode

您可以使用以下命令运行该命令:

php dynacover cover generate
Enter fullscreen mode Exit fullscreen mode

完成后,检查应用程序的根目录以查看生成的图像。它应该类似于以下内容:

封面图片示例

当然,您可以随意自定义图片和占位符的位置。只需记住相应地调整坐标即可。Dynacover GitHub 仓库中还有其他一些封面模板。

一旦您对生成的封面感到满意,您就可以继续执行命令来更新您的推特封面。

4. 以编程方式更新 Twitter 封面图片

现在唯一缺少的是使用 API 实际更新 Twitter 个人资料中的封面图片的部分。

app/Command/Cover在里面创建一个名为 的新命令控制器UpdateController

以下控制者将:

1) 调用dynacover cover generate命令以确保我们有要上传的更新图像2) 使用 TwitterOAuth 库和/account/update_profile_banner
端点 将新图像发布到 Twitter

#app/Command/Cover/UpdateController
<?php

namespace App\Command\Cover;

use Abraham\TwitterOAuth\TwitterOAuth;
use Minicli\Command\CommandController;

class UpdateController extends CommandController
{
    public function handle()
    {
        $banner_path = __DIR__ . '/../../../latest_header.png';
        $this->getPrinter()->info("Generating new cover...");
        $this->getApp()->runCommand(['dynacover', 'cover', 'generate']);

        $api_token = $this->getApp()->config->twitter_consumer_key;
        $api_secret = $this->getApp()->config->twitter_consumer_secret;
        $access_token = $this->getApp()->config->twitter_user_token;
        $token_secret = $this->getApp()->config->twitter_token_secret;

        $client = new TwitterOAuth($api_token, $api_secret, $access_token, $token_secret);

        $post = [
            'width' => 1500,
            'height' => 500,
            'offset_top' => 0,
            'offset_left' => 0,
            'banner' => base64_encode(file_get_contents($banner_path))
        ];

        $this->getPrinter()->info("Uploading cover to Twitter...");
        $client->post('/account/update_profile_banner', $post);

        $this->getPrinter()->info("Finished uploading new banner.");
        return 0;
    }
}
Enter fullscreen mode Exit fullscreen mode

设置好此控制器后,您可以运行:

php dynacover cover update
Enter fullscreen mode Exit fullscreen mode

然后检查您的 Twitter 个人资料以验证新封面是否已上传。

5. 在 Crontab 中包含脚本(可选)

自动生成封面的最后一步是将更新脚本包含在 Crontab 或同等程序中,以一定的固定间隔运行(例如每 5 或 10 分钟)。

我已将 Crontab 设置为每 5 分钟运行一次,以下是我执行的操作:

crontab -e
Enter fullscreen mode Exit fullscreen mode

这将为您的用户打开一个包含 crontab 的文本编辑器。以下行将每 5 分钟(*/5)执行一次指定的命令,并将输出发送到/dev/null

*/5 * * * * /usr/bin/php /home/erika/dynacover/dynacover cover update > /dev/null 2>&1
Enter fullscreen mode Exit fullscreen mode

保存并退出后,新的 crontab 将被安装。请注意,此设置应在远程实时服务器上进行,使用本地计算机运行计划脚本不太可靠php。请始终对可执行文件和脚本使用完整路径dynacover

结论

在本教程中,我们了解了如何以编程方式生成 Twitter 封面/标题图像并将其上传到您的个人资料,以便您可以显示您的最新关注者。

虽然本指南的主题是 Twitter 粉丝和 Twitter 个人资料标题图片,但同样的原则也适用于为其他网络生成图片并使用其他 API。查看dynacover GitHub获取一些思路。

PHP GD 库非常强大,这只是我们可以用它构建的有趣事物的冰山一角!

我希望您喜欢本教程,并请在实施后分享您的个人资料:)

文章来源:https://dev.to/erikaheidi/how-to-dynamically-update-twitter-cover-image-to-show-latest-followers-using-php-gd-and-twitteroauth-62n
PREV
通用化是否会扼杀软件行业的创造力?
NEXT
文档 101:为你的软件项目创建一个好的 README