SlideShare a Scribd company logo
1 of 63
Download to read offline
Laravel SPAM
(Shengyou Fan)
PHP Day #56
2020/10/29
Photo by Pau Casals on Unsplash
— {
"name": "shengyou/self-introduction",
"description": "Self intro for PHP meetup",
"authors": [
{
"name": " (Shengyou Fan)",
"company": "JetBrains",
"role": "Developer Advocate",
"email": "shengyou.fan@jetbrains.com",
"homepage": "https://kraftsman.tw"
}
],
"support": {
"facebook": "https://fb.me/shengyoufan",
"telegram": "@shengyou",
"line": "shengyoufan"
}
}
Composer 2.0
—
$ composer self-update --2
!
Composer
—
Composer
2 Tips …
Tips
—
https://tw.intellij.tips https://tw.kotlin.tips
Web Laravel
PhpStorm
$ artisan make:migration
$ artisan migrate
class Create...Table extends Migration
{
public function up()
{
Schema::create('...', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email');
$table->string('mobile')->nullable();
$table->text('message');
$table->timestamps();
});
}
// ...
}
Migration
—
Model
—
class Feedback extends Model
{
use HasFactory;
protected $table = '...';
protected $fillable = [
'name',
'email',
'mobile',
'message',
];
protected $casts = [
'name' => 'string',
'email' => 'string',
'mobile' => 'string',
'message' => 'string',
];
}
$ artisan make:model
Factory
—
class FeedbackFactory extends Factory
{
protected $model = Feedback::class;
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->email,
'mobile' => $this->faker->phoneNumber,
'message' => $this->faker->sentence,
];
}
}
$ artisan make:factory
Seeder
—
class FeedbackSeeder extends Seeder
{
public function run()
{
Feedback::truncate();
Feedback::factory(10)->create();
}
}
class DatabaseSeeder extends Seeder
{
public function run()
{
$this->call(FeedbackSeeder::class);
}
}
$ artisan make:seeder
$ artisan db:seed
View
—
@if ($message = session()->get('success'))
<div>
{{ $message }}
</div>
@endisset
<form action="{{ route('contact.store') }}" method="POST">
@csrf
<div class="control-group form-group">
<div class="controls">
<label for="name"> </label>
<input type="text" class="form-control"
id="name" name="name"
value="{{ old('name') }}" required>
@error('name')
<p class="invalid-feedback">{{ $message }}</p>
@enderror
</div>
</div>
// ...
</form>
Form Request
—
class FeedbackRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|min:2|max:255',
'email' => 'required|email',
'mobile' => 'nullable|min:10|max:10',
'message' => 'required',
];
}
}
$ artisan make:request
Controller
—
class ContactController extends Controller
{
public function index()
{
return view('contact.index');
}
public function store(FeedbackRequest $request)
{
Feedback::create($request->all());
return redirect()->route('contact.index')
->with('success', '...');
}
}
$ artisan make:controller
Route
—
Route::get('contact', [ContactController::class, 'index'])
->name('contact.index');
Route::post('contact', [ContactController::class, 'store'])
->name('contact.store');
…
Photo by Hannes Johnson on Unsplash
…
!
Google
—
• Google Recaptcha
Recaptcha
—
v1 v2
josiasmontag/laravel-recaptchav3
—
ReCaptcha
—
www.google.com/recaptcha
/
—
// config/recaptchav3.php
return [
'origin' => env('RECAPTCHAV3_ORIGIN', ''),
'sitekey' => env('RECAPTCHAV3_SITEKEY', ''),
'secret' => env('RECAPTCHAV3_SECRET', '')
];
// .env
RECAPTCHAV3_SITEKEY=sitekey
RECAPTCHAV3_SECRET=secret
$ composer require
$ artisan vendor:publish
View
—
@section('page-script')
{!! RecaptchaV3::initJs() !!}
@endsection
@section('page-content')
<form action="{{ route('contact.store') }}" method="POST">
// ...
{!! RecaptchaV3::field('contact') !!}
// ...
@if ($errors->get('g-recaptcha-response'))
<p>{{ $errors->first('g-recaptcha-response') }}</p>
@endif
// ...
</form>
@endsection
Validation
—
// app/Http/Requests/FeedbackRequest.php
class FeedbackRequest extends FormRequest
{
public function rules()
{
return [
'name' => 'required|min:2|max:255',
'email' => 'required|email',
'mobile' => 'nullable|min:10|max:10',
'message' => 'required',
'g-recaptcha-response' => 'recaptchav3:contact,0.5'
];
}
}
// resources/lang/en/validation.php
'custom' => [
'g-recaptcha-response' => [
'recaptchav3' => '...',
],
],
Badge
—
@section('page-style')
<style>
.grecaptcha-badge { visibility: hidden; }
</style>
@endsection
@section('page-content')
This site is protected by ReCaptcha and the Google <a
href="https://policies.google.com/privacy">Privacy Policy</a>
and <a href="https://policies.google.com/terms">Terms of
Service</a> apply.
@endsection
…
—
• Google Recaptcha
• Honeypot
Honeypot
—
•
•
• CSS Honeypot
•
spatie/laravel-honeypot
—
/
—
return [
'name_field_name' => env('HONEYPOT_NAME', ‘my_name'),
'randomize_name_field_name' => env('...', true),
'valid_from_timestamp' => env('...', true),
'valid_from_field_name' => env('...', 'valid_from'),
'amount_of_seconds' => env('...', 1),
'respond_to_spam_with' => BlankPageResponder::class,
'honeypot_fields_required_for_all_forms' => false,
'enabled' => env('HONEYPOT_ENABLED', true),
];
$ composer require
$ artisan vendor:publish
View
—
<form action="{{ route('contact.store') }}" method="POST">
// ...
@honeypot
// ...
</form>
Route
—
Route::post('contact', [ContactController::class, 'store'])
->middleware(ProtectAgainstSpam::class)
->name('contact.store');
—
return [
// ...
'amount_of_seconds' => env('...', 5),
// ...
];
—
return [
'respond_to_spam_with' => SpamPageResponder::class,
];
Responder
—
class SpamPageResponder implements SpamResponder
{
public function respond(Request $request, Closure $next)
{
return response()->view('spam.index');
}
}
( _ )
—
• Google Recaptcha
• Honeypot
• Akismet
Akismet
—
• Wordpress SPAM
•
https://akismet.com/
nickurt/laravel-akismet
—
/
—
// config/akismet.php
return [
'api_key' => env('AKISMET_APIKEY', ''),
'blog_url' => env('AKISMET_BLOGURL', null),
];
// .env
AKISMET_APIKEY=my_akismet_api_key
AKISMET_BLOGURL=http://site_url
$ composer require
$ artisan vendor:publish
View
—
<input type="hidden" name="akismet" value="akismet">
@error('akismet')
<p class="invalid-feedback">{{ $message }}</p>
@enderror
Form Request
—
class FeedbackRequest extends FormRequest
{
// ...
public function rules()
{
return [
'name' => 'required|min:2|max:255',
'email' => 'required|email',
'mobile' => 'nullable|min:10|max:10',
'message' => 'required',
'akismet' => [new AkismetRule(
request()->input('email'),
request()->input('name')
)]
];
}
}
API
"
—
// Migration
Schema::table('feedback', function (Blueprint $table) {
$table->boolean('flag_as_spam')
->default(false)
->after('message');
});
// Model
class Feedback extends Model
{
protected $fillable = [
// ...
'flag_as_spam',
];
protected $casts = [
// ...
'flag_as_spam' => 'boolean',
];
}
$ artisan create:migration
Service
—
class AkismetDetectionService
{
private $akismet;
public function __construct(Akismet $akismet)
{
$this->akismet = $akismet;
}
public function checkContactMessage(
string $name, string $email, string $message
): bool {
if ($this->akismet->validateKey()) {
$this->akismet->setCommentType('contact-form')
->setCommentAuthor($name)
->setCommentAuthorEmail($email)
->setCommentContent($message);
return $this->akismet->isSpam();
}
return true;
}
}
Controller
—
class ContactController extends Controller
{
public function store(
FeedbackRequest $request,
AkismetDetectionService $akismet
) {
$spamDetectResult = $akismet->checkContactMessage(
$request->input('name'),
$request->input('email'),
$request->input('message'),
);
$attributes = array_merge(
$request->only(['name', 'email', ‘message']),
['flag_as_spam' => $spamDetectResult]
);
Feedback::create($attributes);
// ...
}
}
Stop Forum Spam
—
• SPAM
• username email IP…
https://www.stopforumspam.com
nickurt/laravel-stopforumspam
—
—
•
• SPAM SPAM
• SPAM
…
"
…
#
$
xxxxxxxxxxxxx@gnail.com
yyyyyyy@qq.con
cccccccccc@yahoo.comn
zzzzzz@164.com
aaaaaaaaaaa@gmail.cm
wwwww@hotmaiI.com
xxxxxxxxxxxxx@gnail.com
yyyyyyy@qq.con
cccccccccc@yahoo.comn
zzzzzz@164.com
aaaaaaaaaaa@gmail.cm
wwwww@hotmaiI.com
Email
Photo by Tobias Tullius on Unsplash
intellij.tips
JetBrains
—
—
Shengyou Fan ( )
shengyou.fan@jetbrains.com
Q&A
—
Laravel SPAM

More Related Content

What's hot

Rails Presentation (Anton Dmitriyev)
Rails Presentation (Anton Dmitriyev)Rails Presentation (Anton Dmitriyev)
Rails Presentation (Anton Dmitriyev)True-Vision
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryTatsuhiko Miyagawa
 
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other ToolsCool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other ToolsRyan Weaver
 
Using Ansible as Makefiles to unite your developers
Using Ansible as Makefiles to unite your developersUsing Ansible as Makefiles to unite your developers
Using Ansible as Makefiles to unite your developersthiagoalessio
 
Lights, Camera, Docker: Streaming Video at DramaFever
Lights, Camera, Docker: Streaming Video at DramaFeverLights, Camera, Docker: Streaming Video at DramaFever
Lights, Camera, Docker: Streaming Video at DramaFeverbridgetkromhout
 
Operation Oriented Web Applications / Yokohama pm7
Operation Oriented Web Applications / Yokohama pm7Operation Oriented Web Applications / Yokohama pm7
Operation Oriented Web Applications / Yokohama pm7Masahiro Nagano
 
Testing your infrastructure with litmus
Testing your infrastructure with litmusTesting your infrastructure with litmus
Testing your infrastructure with litmusBram Vogelaar
 
Node.js Express
Node.js  ExpressNode.js  Express
Node.js ExpressEyal Vardi
 
Inside Bokete: Web Application with Mojolicious and others
Inside Bokete:  Web Application with Mojolicious and othersInside Bokete:  Web Application with Mojolicious and others
Inside Bokete: Web Application with Mojolicious and othersYusuke Wada
 
MeaNstack on Docker
MeaNstack on DockerMeaNstack on Docker
MeaNstack on DockerDaniel Ku
 
HTML5 tutorial: canvas, offfline & sockets
HTML5 tutorial: canvas, offfline & socketsHTML5 tutorial: canvas, offfline & sockets
HTML5 tutorial: canvas, offfline & socketsRemy Sharp
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Racksickill
 
Integration Test Cucumber + Webrat + Selenium
Integration Test Cucumber + Webrat + SeleniumIntegration Test Cucumber + Webrat + Selenium
Integration Test Cucumber + Webrat + Seleniumtka
 

What's hot (20)

Plack - LPW 2009
Plack - LPW 2009Plack - LPW 2009
Plack - LPW 2009
 
Rails Presentation (Anton Dmitriyev)
Rails Presentation (Anton Dmitriyev)Rails Presentation (Anton Dmitriyev)
Rails Presentation (Anton Dmitriyev)
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
 
Triple Blitz Strike
Triple Blitz StrikeTriple Blitz Strike
Triple Blitz Strike
 
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other ToolsCool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
 
Using Ansible as Makefiles to unite your developers
Using Ansible as Makefiles to unite your developersUsing Ansible as Makefiles to unite your developers
Using Ansible as Makefiles to unite your developers
 
Developing apps using Perl
Developing apps using PerlDeveloping apps using Perl
Developing apps using Perl
 
Write php deploy everywhere
Write php deploy everywhereWrite php deploy everywhere
Write php deploy everywhere
 
Lights, Camera, Docker: Streaming Video at DramaFever
Lights, Camera, Docker: Streaming Video at DramaFeverLights, Camera, Docker: Streaming Video at DramaFever
Lights, Camera, Docker: Streaming Video at DramaFever
 
Operation Oriented Web Applications / Yokohama pm7
Operation Oriented Web Applications / Yokohama pm7Operation Oriented Web Applications / Yokohama pm7
Operation Oriented Web Applications / Yokohama pm7
 
Testing your infrastructure with litmus
Testing your infrastructure with litmusTesting your infrastructure with litmus
Testing your infrastructure with litmus
 
Write php deploy everywhere tek11
Write php deploy everywhere   tek11Write php deploy everywhere   tek11
Write php deploy everywhere tek11
 
Node.js Express
Node.js  ExpressNode.js  Express
Node.js Express
 
Inside Bokete: Web Application with Mojolicious and others
Inside Bokete:  Web Application with Mojolicious and othersInside Bokete:  Web Application with Mojolicious and others
Inside Bokete: Web Application with Mojolicious and others
 
MeaNstack on Docker
MeaNstack on DockerMeaNstack on Docker
MeaNstack on Docker
 
HTML5 tutorial: canvas, offfline & sockets
HTML5 tutorial: canvas, offfline & socketsHTML5 tutorial: canvas, offfline & sockets
HTML5 tutorial: canvas, offfline & sockets
 
Composer
ComposerComposer
Composer
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Rack
 
Express JS
Express JSExpress JS
Express JS
 
Integration Test Cucumber + Webrat + Selenium
Integration Test Cucumber + Webrat + SeleniumIntegration Test Cucumber + Webrat + Selenium
Integration Test Cucumber + Webrat + Selenium
 

Similar to [PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史

Django - Framework web para perfeccionistas com prazos
Django - Framework web para perfeccionistas com prazosDjango - Framework web para perfeccionistas com prazos
Django - Framework web para perfeccionistas com prazosIgor Sobreira
 
Spca2014 hillier 3rd party_javascript_libraries
Spca2014 hillier 3rd party_javascript_librariesSpca2014 hillier 3rd party_javascript_libraries
Spca2014 hillier 3rd party_javascript_librariesNCCOMMS
 
Mitigate Maliciousness -- jQuery Europe 2013
Mitigate Maliciousness -- jQuery Europe 2013Mitigate Maliciousness -- jQuery Europe 2013
Mitigate Maliciousness -- jQuery Europe 2013Mike West
 
Intro to Php Security
Intro to Php SecurityIntro to Php Security
Intro to Php SecurityDave Ross
 
FamilySearch Reference Client
FamilySearch Reference ClientFamilySearch Reference Client
FamilySearch Reference ClientDallan Quass
 
REST with Eve and Python
REST with Eve and PythonREST with Eve and Python
REST with Eve and PythonPiXeL16
 
Presentation html5 css3 by thibaut
Presentation html5 css3 by thibautPresentation html5 css3 by thibaut
Presentation html5 css3 by thibautThibaut Baillet
 
LaravelConf Taiwan 2018 套件發表會 - 飛信資訊 SMTP 及 SMS SDK
LaravelConf Taiwan 2018 套件發表會 - 飛信資訊 SMTP 及 SMS SDKLaravelConf Taiwan 2018 套件發表會 - 飛信資訊 SMTP 及 SMS SDK
LaravelConf Taiwan 2018 套件發表會 - 飛信資訊 SMTP 及 SMS SDKShengyou Fan
 
Bootstrap 3 in Joomla!
Bootstrap 3 in Joomla!Bootstrap 3 in Joomla!
Bootstrap 3 in Joomla!Hans Kuijpers
 
Simple Web Apps With Sinatra
Simple Web Apps With SinatraSimple Web Apps With Sinatra
Simple Web Apps With Sinatraa_l
 
Private slideshow
Private slideshowPrivate slideshow
Private slideshowsblackman
 
Survey of Front End Topics in Rails
Survey of Front End Topics in RailsSurvey of Front End Topics in Rails
Survey of Front End Topics in RailsBenjamin Vandgrift
 
Evolution Of Web Security
Evolution Of Web SecurityEvolution Of Web Security
Evolution Of Web SecurityChris Shiflett
 
PHP SA 2014 - Releasing Your Open Source Project
PHP SA 2014 - Releasing Your Open Source ProjectPHP SA 2014 - Releasing Your Open Source Project
PHP SA 2014 - Releasing Your Open Source Projectxsist10
 
Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)
Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)
Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)Dotan Dimet
 

Similar to [PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史 (20)

Django - Framework web para perfeccionistas com prazos
Django - Framework web para perfeccionistas com prazosDjango - Framework web para perfeccionistas com prazos
Django - Framework web para perfeccionistas com prazos
 
Spca2014 hillier 3rd party_javascript_libraries
Spca2014 hillier 3rd party_javascript_librariesSpca2014 hillier 3rd party_javascript_libraries
Spca2014 hillier 3rd party_javascript_libraries
 
Blog Hacks 2011
Blog Hacks 2011Blog Hacks 2011
Blog Hacks 2011
 
Mitigate Maliciousness -- jQuery Europe 2013
Mitigate Maliciousness -- jQuery Europe 2013Mitigate Maliciousness -- jQuery Europe 2013
Mitigate Maliciousness -- jQuery Europe 2013
 
Intro to Php Security
Intro to Php SecurityIntro to Php Security
Intro to Php Security
 
FamilySearch Reference Client
FamilySearch Reference ClientFamilySearch Reference Client
FamilySearch Reference Client
 
REST with Eve and Python
REST with Eve and PythonREST with Eve and Python
REST with Eve and Python
 
Presentation html5 css3 by thibaut
Presentation html5 css3 by thibautPresentation html5 css3 by thibaut
Presentation html5 css3 by thibaut
 
LaravelConf Taiwan 2018 套件發表會 - 飛信資訊 SMTP 及 SMS SDK
LaravelConf Taiwan 2018 套件發表會 - 飛信資訊 SMTP 及 SMS SDKLaravelConf Taiwan 2018 套件發表會 - 飛信資訊 SMTP 及 SMS SDK
LaravelConf Taiwan 2018 套件發表會 - 飛信資訊 SMTP 及 SMS SDK
 
PhpBB meets Symfony2
PhpBB meets Symfony2PhpBB meets Symfony2
PhpBB meets Symfony2
 
Bootstrap 3 in Joomla!
Bootstrap 3 in Joomla!Bootstrap 3 in Joomla!
Bootstrap 3 in Joomla!
 
Simple Web Apps With Sinatra
Simple Web Apps With SinatraSimple Web Apps With Sinatra
Simple Web Apps With Sinatra
 
Mojolicious
MojoliciousMojolicious
Mojolicious
 
Private slideshow
Private slideshowPrivate slideshow
Private slideshow
 
Ruby gems
Ruby gemsRuby gems
Ruby gems
 
Survey of Front End Topics in Rails
Survey of Front End Topics in RailsSurvey of Front End Topics in Rails
Survey of Front End Topics in Rails
 
Evolution Of Web Security
Evolution Of Web SecurityEvolution Of Web Security
Evolution Of Web Security
 
Ams adapters
Ams adaptersAms adapters
Ams adapters
 
PHP SA 2014 - Releasing Your Open Source Project
PHP SA 2014 - Releasing Your Open Source ProjectPHP SA 2014 - Releasing Your Open Source Project
PHP SA 2014 - Releasing Your Open Source Project
 
Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)
Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)
Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)
 

More from Shengyou Fan

[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式Shengyou Fan
 
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...Shengyou Fan
 
[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀
[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀
[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀Shengyou Fan
 
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能Shengyou Fan
 
How I make a podcast website using serverless technology in 2023
How I make a podcast website using serverless technology in 2023How I make a podcast website using serverless technology in 2023
How I make a podcast website using serverless technology in 2023Shengyou Fan
 
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀Shengyou Fan
 
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台Shengyou Fan
 
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇Shengyou Fan
 
Using the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your DatabaseUsing the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your DatabaseShengyou Fan
 
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具Shengyou Fan
 
[COSCUP 2022] Kotlin Collection 遊樂園
[COSCUP 2022] Kotlin Collection 遊樂園[COSCUP 2022] Kotlin Collection 遊樂園
[COSCUP 2022] Kotlin Collection 遊樂園Shengyou Fan
 
初探 Kotlin Multiplatform
初探 Kotlin Multiplatform初探 Kotlin Multiplatform
初探 Kotlin MultiplatformShengyou Fan
 
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率Shengyou Fan
 
[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南Shengyou Fan
 
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用Shengyou Fan
 
老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具Shengyou Fan
 
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS AggregatorShengyou Fan
 
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON APIShengyou Fan
 
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin ServerlessShengyou Fan
 
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置Shengyou Fan
 

More from Shengyou Fan (20)

[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
 
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...
 
[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀
[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀
[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀
 
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
 
How I make a podcast website using serverless technology in 2023
How I make a podcast website using serverless technology in 2023How I make a podcast website using serverless technology in 2023
How I make a podcast website using serverless technology in 2023
 
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
 
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
 
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
 
Using the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your DatabaseUsing the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your Database
 
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
 
[COSCUP 2022] Kotlin Collection 遊樂園
[COSCUP 2022] Kotlin Collection 遊樂園[COSCUP 2022] Kotlin Collection 遊樂園
[COSCUP 2022] Kotlin Collection 遊樂園
 
初探 Kotlin Multiplatform
初探 Kotlin Multiplatform初探 Kotlin Multiplatform
初探 Kotlin Multiplatform
 
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
 
[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南
 
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
 
老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具
 
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
 
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
 
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
 
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
 

Recently uploaded

Elevate Your Business with Our IT Expertise in New Orleans
Elevate Your Business with Our IT Expertise in New OrleansElevate Your Business with Our IT Expertise in New Orleans
Elevate Your Business with Our IT Expertise in New Orleanscorenetworkseo
 
办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书
办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书
办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书zdzoqco
 
Contact Rya Baby for Call Girls New Delhi
Contact Rya Baby for Call Girls New DelhiContact Rya Baby for Call Girls New Delhi
Contact Rya Baby for Call Girls New Delhimiss dipika
 
Call Girls Near The Suryaa Hotel New Delhi 9873777170
Call Girls Near The Suryaa Hotel New Delhi 9873777170Call Girls Near The Suryaa Hotel New Delhi 9873777170
Call Girls Near The Suryaa Hotel New Delhi 9873777170Sonam Pathan
 
Call Girls In The Ocean Pearl Retreat Hotel New Delhi 9873777170
Call Girls In The Ocean Pearl Retreat Hotel New Delhi 9873777170Call Girls In The Ocean Pearl Retreat Hotel New Delhi 9873777170
Call Girls In The Ocean Pearl Retreat Hotel New Delhi 9873777170Sonam Pathan
 
『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书
『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书
『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书rnrncn29
 
A Good Girl's Guide to Murder (A Good Girl's Guide to Murder, #1)
A Good Girl's Guide to Murder (A Good Girl's Guide to Murder, #1)A Good Girl's Guide to Murder (A Good Girl's Guide to Murder, #1)
A Good Girl's Guide to Murder (A Good Girl's Guide to Murder, #1)Christopher H Felton
 
SCM Symposium PPT Format Customer loyalty is predi
SCM Symposium PPT Format Customer loyalty is prediSCM Symposium PPT Format Customer loyalty is predi
SCM Symposium PPT Format Customer loyalty is predieusebiomeyer
 
Git and Github workshop GDSC MLRITM
Git and Github  workshop GDSC MLRITMGit and Github  workshop GDSC MLRITM
Git and Github workshop GDSC MLRITMgdsc13
 
定制(AUT毕业证书)新西兰奥克兰理工大学毕业证成绩单原版一比一
定制(AUT毕业证书)新西兰奥克兰理工大学毕业证成绩单原版一比一定制(AUT毕业证书)新西兰奥克兰理工大学毕业证成绩单原版一比一
定制(AUT毕业证书)新西兰奥克兰理工大学毕业证成绩单原版一比一Fs
 
定制(UAL学位证)英国伦敦艺术大学毕业证成绩单原版一比一
定制(UAL学位证)英国伦敦艺术大学毕业证成绩单原版一比一定制(UAL学位证)英国伦敦艺术大学毕业证成绩单原版一比一
定制(UAL学位证)英国伦敦艺术大学毕业证成绩单原版一比一Fs
 
Top 10 Interactive Website Design Trends in 2024.pptx
Top 10 Interactive Website Design Trends in 2024.pptxTop 10 Interactive Website Design Trends in 2024.pptx
Top 10 Interactive Website Design Trends in 2024.pptxDyna Gilbert
 
Blepharitis inflammation of eyelid symptoms cause everything included along w...
Blepharitis inflammation of eyelid symptoms cause everything included along w...Blepharitis inflammation of eyelid symptoms cause everything included along w...
Blepharitis inflammation of eyelid symptoms cause everything included along w...Excelmac1
 
Packaging the Monolith - PHP Tek 2024 (Breaking it down one bite at a time)
Packaging the Monolith - PHP Tek 2024 (Breaking it down one bite at a time)Packaging the Monolith - PHP Tek 2024 (Breaking it down one bite at a time)
Packaging the Monolith - PHP Tek 2024 (Breaking it down one bite at a time)Dana Luther
 
PHP-based rendering of TYPO3 Documentation
PHP-based rendering of TYPO3 DocumentationPHP-based rendering of TYPO3 Documentation
PHP-based rendering of TYPO3 DocumentationLinaWolf1
 
定制(Management毕业证书)新加坡管理大学毕业证成绩单原版一比一
定制(Management毕业证书)新加坡管理大学毕业证成绩单原版一比一定制(Management毕业证书)新加坡管理大学毕业证成绩单原版一比一
定制(Management毕业证书)新加坡管理大学毕业证成绩单原版一比一Fs
 
Font Performance - NYC WebPerf Meetup April '24
Font Performance - NYC WebPerf Meetup April '24Font Performance - NYC WebPerf Meetup April '24
Font Performance - NYC WebPerf Meetup April '24Paul Calvano
 

Recently uploaded (20)

Elevate Your Business with Our IT Expertise in New Orleans
Elevate Your Business with Our IT Expertise in New OrleansElevate Your Business with Our IT Expertise in New Orleans
Elevate Your Business with Our IT Expertise in New Orleans
 
办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书
办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书
办理多伦多大学毕业证成绩单|购买加拿大UTSG文凭证书
 
Hot Sexy call girls in Rk Puram 🔝 9953056974 🔝 Delhi escort Service
Hot Sexy call girls in  Rk Puram 🔝 9953056974 🔝 Delhi escort ServiceHot Sexy call girls in  Rk Puram 🔝 9953056974 🔝 Delhi escort Service
Hot Sexy call girls in Rk Puram 🔝 9953056974 🔝 Delhi escort Service
 
Contact Rya Baby for Call Girls New Delhi
Contact Rya Baby for Call Girls New DelhiContact Rya Baby for Call Girls New Delhi
Contact Rya Baby for Call Girls New Delhi
 
Call Girls Near The Suryaa Hotel New Delhi 9873777170
Call Girls Near The Suryaa Hotel New Delhi 9873777170Call Girls Near The Suryaa Hotel New Delhi 9873777170
Call Girls Near The Suryaa Hotel New Delhi 9873777170
 
Call Girls In The Ocean Pearl Retreat Hotel New Delhi 9873777170
Call Girls In The Ocean Pearl Retreat Hotel New Delhi 9873777170Call Girls In The Ocean Pearl Retreat Hotel New Delhi 9873777170
Call Girls In The Ocean Pearl Retreat Hotel New Delhi 9873777170
 
『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书
『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书
『澳洲文凭』买拉筹伯大学毕业证书成绩单办理澳洲LTU文凭学位证书
 
A Good Girl's Guide to Murder (A Good Girl's Guide to Murder, #1)
A Good Girl's Guide to Murder (A Good Girl's Guide to Murder, #1)A Good Girl's Guide to Murder (A Good Girl's Guide to Murder, #1)
A Good Girl's Guide to Murder (A Good Girl's Guide to Murder, #1)
 
SCM Symposium PPT Format Customer loyalty is predi
SCM Symposium PPT Format Customer loyalty is prediSCM Symposium PPT Format Customer loyalty is predi
SCM Symposium PPT Format Customer loyalty is predi
 
Git and Github workshop GDSC MLRITM
Git and Github  workshop GDSC MLRITMGit and Github  workshop GDSC MLRITM
Git and Github workshop GDSC MLRITM
 
定制(AUT毕业证书)新西兰奥克兰理工大学毕业证成绩单原版一比一
定制(AUT毕业证书)新西兰奥克兰理工大学毕业证成绩单原版一比一定制(AUT毕业证书)新西兰奥克兰理工大学毕业证成绩单原版一比一
定制(AUT毕业证书)新西兰奥克兰理工大学毕业证成绩单原版一比一
 
young call girls in Uttam Nagar🔝 9953056974 🔝 Delhi escort Service
young call girls in Uttam Nagar🔝 9953056974 🔝 Delhi escort Serviceyoung call girls in Uttam Nagar🔝 9953056974 🔝 Delhi escort Service
young call girls in Uttam Nagar🔝 9953056974 🔝 Delhi escort Service
 
定制(UAL学位证)英国伦敦艺术大学毕业证成绩单原版一比一
定制(UAL学位证)英国伦敦艺术大学毕业证成绩单原版一比一定制(UAL学位证)英国伦敦艺术大学毕业证成绩单原版一比一
定制(UAL学位证)英国伦敦艺术大学毕业证成绩单原版一比一
 
Top 10 Interactive Website Design Trends in 2024.pptx
Top 10 Interactive Website Design Trends in 2024.pptxTop 10 Interactive Website Design Trends in 2024.pptx
Top 10 Interactive Website Design Trends in 2024.pptx
 
Blepharitis inflammation of eyelid symptoms cause everything included along w...
Blepharitis inflammation of eyelid symptoms cause everything included along w...Blepharitis inflammation of eyelid symptoms cause everything included along w...
Blepharitis inflammation of eyelid symptoms cause everything included along w...
 
Packaging the Monolith - PHP Tek 2024 (Breaking it down one bite at a time)
Packaging the Monolith - PHP Tek 2024 (Breaking it down one bite at a time)Packaging the Monolith - PHP Tek 2024 (Breaking it down one bite at a time)
Packaging the Monolith - PHP Tek 2024 (Breaking it down one bite at a time)
 
PHP-based rendering of TYPO3 Documentation
PHP-based rendering of TYPO3 DocumentationPHP-based rendering of TYPO3 Documentation
PHP-based rendering of TYPO3 Documentation
 
定制(Management毕业证书)新加坡管理大学毕业证成绩单原版一比一
定制(Management毕业证书)新加坡管理大学毕业证成绩单原版一比一定制(Management毕业证书)新加坡管理大学毕业证成绩单原版一比一
定制(Management毕业证书)新加坡管理大学毕业证成绩单原版一比一
 
Model Call Girl in Jamuna Vihar Delhi reach out to us at 🔝9953056974🔝
Model Call Girl in  Jamuna Vihar Delhi reach out to us at 🔝9953056974🔝Model Call Girl in  Jamuna Vihar Delhi reach out to us at 🔝9953056974🔝
Model Call Girl in Jamuna Vihar Delhi reach out to us at 🔝9953056974🔝
 
Font Performance - NYC WebPerf Meetup April '24
Font Performance - NYC WebPerf Meetup April '24Font Performance - NYC WebPerf Meetup April '24
Font Performance - NYC WebPerf Meetup April '24
 

[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史