@artilingo/artiframe-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/logo.png +0 -0
- package/assets/logo.svg +22 -0
- package/assets/logo.webp +0 -0
- package/assets/logo@0.5x.png +0 -0
- package/assets/logo@0.75x.png +0 -0
- package/assets/logo@1.5x.png +0 -0
- package/assets/logo@2x.png +0 -0
- package/assets/logo@3x.png +0 -0
- package/assets/logo@4x.png +0 -0
- package/bin/artiframe.js +57 -0
- package/bin/artiframe.php +45 -0
- package/core-stubs/app/ApiControl.php +81 -0
- package/core-stubs/app/Database.php +69 -0
- package/core-stubs/app/DotEnv.php +63 -0
- package/core-stubs/app/R2Manager.php +130 -0
- package/core-stubs/app/ViewControl.php +24 -0
- package/core-stubs/bin/SystemMethod.php +271 -0
- package/core-stubs/bin/ViewMethod.php +354 -0
- package/core-stubs/docs/de.html +951 -0
- package/core-stubs/docs/en.html +952 -0
- package/core-stubs/docs/es.html +947 -0
- package/core-stubs/docs/fr.html +850 -0
- package/core-stubs/docs/tr.html +951 -0
- package/core-stubs/public/assets/css/components/footer.css +0 -0
- package/core-stubs/public/assets/css/components/header.css +0 -0
- package/core-stubs/public/assets/css/components/mobilenav.css +0 -0
- package/core-stubs/public/assets/css/components/sidebar.css +0 -0
- package/core-stubs/public/assets/css/components/theme-modal.css +0 -0
- package/core-stubs/public/assets/css/root/app.css +61 -0
- package/core-stubs/public/assets/js/components/header.js +0 -0
- package/core-stubs/public/assets/js/components/mobilenav.js +0 -0
- package/core-stubs/public/assets/js/components/sidebar.js +0 -0
- package/core-stubs/public/assets/js/components/theme-modal.js +0 -0
- package/core-stubs/public/assets/js/root/app.js +30 -0
- package/core-stubs/public/includes/footer.php +5 -0
- package/core-stubs/public/includes/head.php +26 -0
- package/core-stubs/public/includes/header.php +5 -0
- package/core-stubs/public/includes/mobilenav.php +5 -0
- package/core-stubs/public/includes/sidebar.php +5 -0
- package/core-stubs/public/includes/theme-modal.php +5 -0
- package/core-stubs/readme/de.md +29 -0
- package/core-stubs/readme/en.md +29 -0
- package/core-stubs/readme/es.md +29 -0
- package/core-stubs/readme/fr.md +29 -0
- package/core-stubs/readme/tr.md +29 -0
- package/package.json +49 -0
- package/scripts/postinstall.js +21 -0
- package/src/App.php +266 -0
- package/src/Commands/MakeApiCommand.php +71 -0
- package/src/Commands/MakeClassCommand.php +88 -0
- package/src/Commands/MakeViewCommand.php +95 -0
- package/src/Commands/NewProjectCommand.php +633 -0
- package/src/Commands/VersionCommand.php +92 -0
- package/src/Lang/de.php +53 -0
- package/src/Lang/en.php +53 -0
- package/src/Lang/es.php +53 -0
- package/src/Lang/fr.php +53 -0
- package/src/Lang/tr.php +53 -0
- package/src/Services/Safeguard.php +48 -0
- package/src/Services/Translator.php +52 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* ArtiFrame Core Engine
|
|
4
|
+
*
|
|
5
|
+
* @package ArtiFrame
|
|
6
|
+
* @author Artilingo
|
|
7
|
+
* @license AGPLv3 (Attribution-ShareAlike Required)
|
|
8
|
+
* @link https://artiframe.org
|
|
9
|
+
*
|
|
10
|
+
* NOTICE: This file is part of the ArtiFrame ecosystem.
|
|
11
|
+
* Any derivative works or patches MUST retain this original copyright notice
|
|
12
|
+
* and remain open-source under the AGPLv3 license.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
namespace Bin;
|
|
16
|
+
|
|
17
|
+
class SystemMethod
|
|
18
|
+
{
|
|
19
|
+
/**
|
|
20
|
+
* E-posta adresinin format olarak geçerli olup olmadığını doğrular.
|
|
21
|
+
*
|
|
22
|
+
* @param string $email Doğrulanacak E-Posta
|
|
23
|
+
* @return bool
|
|
24
|
+
*/
|
|
25
|
+
public static function verifyEmail(string $email): bool
|
|
26
|
+
{
|
|
27
|
+
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Gelen veriyi güvenli bir Integer (tam sayı) değerine dönüştürür.
|
|
32
|
+
* Harfleri siler ve sayısal karakter bırakır.
|
|
33
|
+
*
|
|
34
|
+
* @param mixed $value
|
|
35
|
+
* @return int
|
|
36
|
+
*/
|
|
37
|
+
public static function sanitizeInt($value): int
|
|
38
|
+
{
|
|
39
|
+
return (int) filter_var($value, FILTER_SANITIZE_NUMBER_INT);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Gelen verideki HTML etiketlerini ve zararlı kodları temizler.
|
|
44
|
+
* Veritabanına String kaydetmeden önce mutlaka kullanılmalıdır.
|
|
45
|
+
*
|
|
46
|
+
* @param string $value
|
|
47
|
+
* @return string
|
|
48
|
+
*/
|
|
49
|
+
public static function sanitizeString(string $value): string
|
|
50
|
+
{
|
|
51
|
+
return strip_tags(trim($value));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Sayfaya gelen isteğin bir form gönderimi (POST) olup olmadığını kontrol eder.
|
|
56
|
+
*
|
|
57
|
+
* @return bool
|
|
58
|
+
*/
|
|
59
|
+
public static function isPost(): bool
|
|
60
|
+
{
|
|
61
|
+
return $_SERVER['REQUEST_METHOD'] === 'POST';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Oturum (Session) tabanlı CSRF (Cross-Site Request Forgery) güvenlik token'ı üretir.
|
|
66
|
+
*/
|
|
67
|
+
public static function generateCsrf(): string
|
|
68
|
+
{
|
|
69
|
+
if (session_status() === PHP_SESSION_NONE) {
|
|
70
|
+
session_start();
|
|
71
|
+
}
|
|
72
|
+
if (empty($_SESSION['csrf_token'])) {
|
|
73
|
+
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
|
74
|
+
}
|
|
75
|
+
return $_SESSION['csrf_token'];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Formdan gelen CSRF token'ın doğruluğunu onaylar. (Form güvenlik kalkanı)
|
|
80
|
+
*/
|
|
81
|
+
public static function verifyCsrf(?string $token): bool
|
|
82
|
+
{
|
|
83
|
+
if (session_status() === PHP_SESSION_NONE) {
|
|
84
|
+
session_start();
|
|
85
|
+
}
|
|
86
|
+
if (empty($_SESSION['csrf_token']) || empty($token)) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
return hash_equals($_SESSION['csrf_token'], $token);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* İsteğin AJAX üzerinden gelip gelmediğini kontrol eder. (Fetch / Axios destekli)
|
|
94
|
+
*/
|
|
95
|
+
public static function isAjax(): bool
|
|
96
|
+
{
|
|
97
|
+
return !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* API'ler için hızlı ve standart JSON yanıt (response) oluşturur.
|
|
102
|
+
* Kullanıldığı anda işlemi sonlandırır (exit).
|
|
103
|
+
*
|
|
104
|
+
* @param array $data JSON'a çevrilecek dizi (array)
|
|
105
|
+
* @param int $statusCode HTTP Durum Kodu (200 OK, 404 Not Found vb.)
|
|
106
|
+
*/
|
|
107
|
+
public static function jsonResponse(array $data, int $statusCode = 200): void
|
|
108
|
+
{
|
|
109
|
+
http_response_code($statusCode);
|
|
110
|
+
header('Content-Type: application/json; charset=utf-8');
|
|
111
|
+
echo json_encode($data, JSON_UNESCAPED_UNICODE);
|
|
112
|
+
exit;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Sayfaya gelen isteğin GET olup olmadığını kontrol eder.
|
|
116
|
+
*/
|
|
117
|
+
public static function isGet(): bool
|
|
118
|
+
{
|
|
119
|
+
return $_SERVER['REQUEST_METHOD'] === 'GET';
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Sayfaya gelen isteğin PUT olup olmadığını kontrol eder.
|
|
124
|
+
*/
|
|
125
|
+
public static function isPut(): bool
|
|
126
|
+
{
|
|
127
|
+
return $_SERVER['REQUEST_METHOD'] === 'PUT';
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Sayfaya gelen isteğin DELETE olup olmadığını kontrol eder.
|
|
132
|
+
*/
|
|
133
|
+
public static function isDelete(): bool
|
|
134
|
+
{
|
|
135
|
+
return $_SERVER['REQUEST_METHOD'] === 'DELETE';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Kullanıcının gerçek IP adresini tespit eder (Cloudflare ve Proxy destekli).
|
|
140
|
+
*/
|
|
141
|
+
public static function getClientIp(): string
|
|
142
|
+
{
|
|
143
|
+
if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
|
|
144
|
+
return $_SERVER['HTTP_CF_CONNECTING_IP'];
|
|
145
|
+
}
|
|
146
|
+
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
|
|
147
|
+
return $_SERVER['HTTP_CLIENT_IP'];
|
|
148
|
+
}
|
|
149
|
+
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
|
150
|
+
$ipList = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
|
|
151
|
+
return trim($ipList[0]);
|
|
152
|
+
}
|
|
153
|
+
return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* İstenilen sayfaya yönlendirme yapar ve çalışmayı durdurur.
|
|
158
|
+
*/
|
|
159
|
+
public static function redirect(string $url): void
|
|
160
|
+
{
|
|
161
|
+
header("Location: " . $url);
|
|
162
|
+
exit;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Kriptografik olarak güvenli, rastgele bir token üretir (Örn: Parola sıfırlama, API Key).
|
|
167
|
+
*/
|
|
168
|
+
public static function generateToken(int $length = 32): string
|
|
169
|
+
{
|
|
170
|
+
return bin2hex(random_bytes($length));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* E-posta adresini zararlı karakterlerden temizler.
|
|
175
|
+
*/
|
|
176
|
+
public static function sanitizeEmail(string $email): string
|
|
177
|
+
{
|
|
178
|
+
return filter_var($email, FILTER_SANITIZE_EMAIL);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Global helper functions for backend methods
|
|
183
|
+
if (!function_exists('verifyEmail')) {
|
|
184
|
+
function verifyEmail(string $email): bool {
|
|
185
|
+
return \Bin\SystemMethod::verifyEmail($email);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!function_exists('sanitizeInt')) {
|
|
190
|
+
function sanitizeInt($value): int {
|
|
191
|
+
return \Bin\SystemMethod::sanitizeInt($value);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (!function_exists('sanitizeString')) {
|
|
196
|
+
function sanitizeString(string $value): string {
|
|
197
|
+
return \Bin\SystemMethod::sanitizeString($value);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (!function_exists('isPost')) {
|
|
202
|
+
function isPost(): bool {
|
|
203
|
+
return \Bin\SystemMethod::isPost();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (!function_exists('jsonResponse')) {
|
|
208
|
+
function jsonResponse(array $data, int $statusCode = 200): void {
|
|
209
|
+
\Bin\SystemMethod::jsonResponse($data, $statusCode);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!function_exists('generateCsrf')) {
|
|
214
|
+
function generateCsrf(): string {
|
|
215
|
+
return \Bin\SystemMethod::generateCsrf();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (!function_exists('verifyCsrf')) {
|
|
220
|
+
function verifyCsrf(?string $token): bool {
|
|
221
|
+
return \Bin\SystemMethod::verifyCsrf($token);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (!function_exists('isAjax')) {
|
|
226
|
+
function isAjax(): bool {
|
|
227
|
+
return \Bin\SystemMethod::isAjax();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (!function_exists('isGet')) {
|
|
232
|
+
function isGet(): bool {
|
|
233
|
+
return \Bin\SystemMethod::isGet();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (!function_exists('isPut')) {
|
|
238
|
+
function isPut(): bool {
|
|
239
|
+
return \Bin\SystemMethod::isPut();
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (!function_exists('isDelete')) {
|
|
244
|
+
function isDelete(): bool {
|
|
245
|
+
return \Bin\SystemMethod::isDelete();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (!function_exists('getClientIp')) {
|
|
250
|
+
function getClientIp(): string {
|
|
251
|
+
return \Bin\SystemMethod::getClientIp();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (!function_exists('redirect')) {
|
|
256
|
+
function redirect(string $url): void {
|
|
257
|
+
\Bin\SystemMethod::redirect($url);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (!function_exists('generateToken')) {
|
|
262
|
+
function generateToken(int $length = 32): string {
|
|
263
|
+
return \Bin\SystemMethod::generateToken($length);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (!function_exists('sanitizeEmail')) {
|
|
268
|
+
function sanitizeEmail(string $email): string {
|
|
269
|
+
return \Bin\SystemMethod::sanitizeEmail($email);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* ArtiFrame Core Engine
|
|
4
|
+
*
|
|
5
|
+
* @package ArtiFrame
|
|
6
|
+
* @author Artilingo
|
|
7
|
+
* @license AGPLv3 (Attribution-ShareAlike Required)
|
|
8
|
+
* @link https://artiframe.org
|
|
9
|
+
*
|
|
10
|
+
* NOTICE: This file is part of the ArtiFrame ecosystem.
|
|
11
|
+
* Any derivative works or patches MUST retain this original copyright notice
|
|
12
|
+
* and remain open-source under the AGPLv3 license.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
namespace Bin;
|
|
16
|
+
|
|
17
|
+
class ViewMethod
|
|
18
|
+
{
|
|
19
|
+
/**
|
|
20
|
+
* Veriyi ekrana yazdırırken XSS saldırılarına karşı temizler (Sanitize).
|
|
21
|
+
* Null değerlerde patlamamak için varsayılan değer döndürür.
|
|
22
|
+
*
|
|
23
|
+
* @param mixed $data Ekrana basılacak veri
|
|
24
|
+
* @param string $default Veri boşsa basılacak varsayılan değer (örn: '-')
|
|
25
|
+
* @return string Güvenli HTML string
|
|
26
|
+
*/
|
|
27
|
+
public static function display($data, string $default = ''): string
|
|
28
|
+
{
|
|
29
|
+
if ($data === null || $data === '') {
|
|
30
|
+
return $default;
|
|
31
|
+
}
|
|
32
|
+
return htmlspecialchars((string)$data, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* URL'leri güvenli hale getirir, zararlı karakterleri temizler.
|
|
37
|
+
*/
|
|
38
|
+
public static function escapeUrl(string $url): string
|
|
39
|
+
{
|
|
40
|
+
return filter_var($url, FILTER_SANITIZE_URL);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Tarih formatını (Veritabanındaki Y-m-d H:i:s formatını) kullanıcı dostu ve güvenli bir şekilde ekrana basar.
|
|
45
|
+
*/
|
|
46
|
+
public static function formatDate(?string $date, string $format = 'd.m.Y H:i'): string
|
|
47
|
+
{
|
|
48
|
+
if (empty($date)) return '-';
|
|
49
|
+
$time = strtotime($date);
|
|
50
|
+
return $time ? date($format, $time) : '-';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Formlar için (XSS ve CSRF korumalı) gizli bir güvenlik token'ı (input) oluşturur.
|
|
55
|
+
*/
|
|
56
|
+
public static function csrfField(): string
|
|
57
|
+
{
|
|
58
|
+
// Require SystemMethod implicitly if it exists in the same namespace context,
|
|
59
|
+
// or just call the global wrapper if it's available. We'll use the class method for purity.
|
|
60
|
+
$token = \Bin\SystemMethod::generateCsrf();
|
|
61
|
+
return '<input type="hidden" name="csrf_token" value="' . self::display($token) . '">';
|
|
62
|
+
}
|
|
63
|
+
// --- Tarih ve Zaman Fonksiyonları ---
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Sadece Günü döndürür (Örn: 24)
|
|
67
|
+
*/
|
|
68
|
+
public static function day($date): string
|
|
69
|
+
{
|
|
70
|
+
if (empty($date)) return '-';
|
|
71
|
+
return date('d', is_numeric($date) ? $date : strtotime($date));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Sadece Ayı rakamla döndürür (Örn: 07)
|
|
76
|
+
*/
|
|
77
|
+
public static function month($date): string
|
|
78
|
+
{
|
|
79
|
+
if (empty($date)) return '-';
|
|
80
|
+
return date('m', is_numeric($date) ? $date : strtotime($date));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Yılı döndürür (Örn: 2026)
|
|
85
|
+
*/
|
|
86
|
+
public static function year($date): string
|
|
87
|
+
{
|
|
88
|
+
if (empty($date)) return '-';
|
|
89
|
+
return date('Y', is_numeric($date) ? $date : strtotime($date));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Saati döndürür (Örn: 14:30)
|
|
94
|
+
*/
|
|
95
|
+
public static function timeOnly($date): string
|
|
96
|
+
{
|
|
97
|
+
if (empty($date)) return '-';
|
|
98
|
+
return date('H:i', is_numeric($date) ? $date : strtotime($date));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Tarihi 24.07.2026 formatında döndürür
|
|
103
|
+
*/
|
|
104
|
+
public static function fulldate($date): string
|
|
105
|
+
{
|
|
106
|
+
if (empty($date)) return '-';
|
|
107
|
+
return date('d.m.Y', is_numeric($date) ? $date : strtotime($date));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Ay isimlerini dile göre döndürür
|
|
112
|
+
*/
|
|
113
|
+
public static function monthName($date, string $lang = 'tr'): string
|
|
114
|
+
{
|
|
115
|
+
if (empty($date)) return '-';
|
|
116
|
+
$m = (int)date('n', is_numeric($date) ? $date : strtotime($date));
|
|
117
|
+
$months = [
|
|
118
|
+
'tr' => ['', 'Ocak', 'Şubat', 'Mart', 'Nisan', 'Mayıs', 'Haziran', 'Temmuz', 'Ağustos', 'Eylül', 'Ekim', 'Kasım', 'Aralık'],
|
|
119
|
+
'en' => ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
|
120
|
+
'de' => ['', 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
|
|
121
|
+
'fr' => ['', 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
|
|
122
|
+
'es' => ['', 'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre']
|
|
123
|
+
];
|
|
124
|
+
$lang = strtolower($lang);
|
|
125
|
+
if (!isset($months[$lang])) $lang = 'en';
|
|
126
|
+
return $months[$lang][$m];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Tarihi yerelleştirilmiş ay ismiyle döndürür (Örn: 24 Temmuz 2026)
|
|
131
|
+
*/
|
|
132
|
+
public static function fulldateName($date, string $lang = 'tr'): string
|
|
133
|
+
{
|
|
134
|
+
if (empty($date)) return '-';
|
|
135
|
+
$time = is_numeric($date) ? $date : strtotime($date);
|
|
136
|
+
$d = date('d', $time);
|
|
137
|
+
$y = date('Y', $time);
|
|
138
|
+
$mName = self::monthName($time, $lang);
|
|
139
|
+
|
|
140
|
+
// İngilizce'de ay öne gelebilir (July 24, 2026) ama basitlik açısından formatı koruyabiliriz veya dile göre değiştirebiliriz.
|
|
141
|
+
if (strtolower($lang) === 'en') {
|
|
142
|
+
return "{$mName} {$d}, {$y}";
|
|
143
|
+
}
|
|
144
|
+
return "{$d} {$mName} {$y}";
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Sosyal medya tarzı zaman gösterimi (Örn: 5 dakika önce)
|
|
149
|
+
*/
|
|
150
|
+
public static function timeAgo($date, string $lang = 'tr'): string
|
|
151
|
+
{
|
|
152
|
+
if (empty($date)) return '-';
|
|
153
|
+
$time = is_numeric($date) ? $date : strtotime($date);
|
|
154
|
+
$diff = time() - $time;
|
|
155
|
+
if ($diff < 1) return ($lang === 'tr') ? 'şimdi' : 'just now';
|
|
156
|
+
|
|
157
|
+
$tokens = [
|
|
158
|
+
31536000 => 'year',
|
|
159
|
+
2592000 => 'month',
|
|
160
|
+
604800 => 'week',
|
|
161
|
+
86400 => 'day',
|
|
162
|
+
3600 => 'hour',
|
|
163
|
+
60 => 'minute',
|
|
164
|
+
1 => 'second'
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
$lang = strtolower($lang);
|
|
168
|
+
$translations = [
|
|
169
|
+
'tr' => ['year'=>'yıl', 'month'=>'ay', 'week'=>'hafta', 'day'=>'gün', 'hour'=>'saat', 'minute'=>'dakika', 'second'=>'saniye', 'ago'=>'önce', 'format'=>'{value} {unit} {ago}'],
|
|
170
|
+
'en' => ['year'=>'year', 'month'=>'month', 'week'=>'week', 'day'=>'day', 'hour'=>'hour', 'minute'=>'minute', 'second'=>'second', 'ago'=>'ago', 'format'=>'{value} {unit}s {ago}'],
|
|
171
|
+
'de' => ['year'=>'Jahr', 'month'=>'Monat', 'week'=>'Woche', 'day'=>'Tag', 'hour'=>'Stunde', 'minute'=>'Minute', 'second'=>'Sekunde', 'ago'=>'vor', 'format'=>'{ago} {value} {unit}en'], // simplified
|
|
172
|
+
'fr' => ['year'=>'an', 'month'=>'mois', 'week'=>'semaine', 'day'=>'jour', 'hour'=>'heure', 'minute'=>'minute', 'second'=>'seconde', 'ago'=>'il y a', 'format'=>'{ago} {value} {unit}s'],
|
|
173
|
+
'es' => ['year'=>'año', 'month'=>'mes', 'week'=>'semana', 'day'=>'día', 'hour'=>'hora', 'minute'=>'minuto', 'second'=>'segundo', 'ago'=>'hace', 'format'=>'{ago} {value} {unit}s']
|
|
174
|
+
];
|
|
175
|
+
if (!isset($translations[$lang])) $lang = 'en';
|
|
176
|
+
|
|
177
|
+
foreach ($tokens as $unit => $text) {
|
|
178
|
+
if ($diff < $unit) continue;
|
|
179
|
+
$numberOfUnits = floor($diff / $unit);
|
|
180
|
+
|
|
181
|
+
// Pluralization logic is basic here, but functional for general use
|
|
182
|
+
$unitStr = $translations[$lang][$text];
|
|
183
|
+
if ($lang === 'en' && $numberOfUnits == 1) $translations['en']['format'] = '{value} {unit} {ago}';
|
|
184
|
+
|
|
185
|
+
$formatted = str_replace(
|
|
186
|
+
['{value}', '{unit}', '{ago}'],
|
|
187
|
+
[$numberOfUnits, $unitStr, $translations[$lang]['ago']],
|
|
188
|
+
$translations[$lang]['format']
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
// Fix DE basic plurals roughly
|
|
192
|
+
if ($lang === 'de') {
|
|
193
|
+
$formatted = str_replace(['Jahren', 'Monaten', 'Wocheen', 'Tagen', 'Stundeen', 'Minuteen', 'Sekundeen'], ['Jahren', 'Monaten', 'Wochen', 'Tagen', 'Stunden', 'Minuten', 'Sekunden'], $formatted);
|
|
194
|
+
}
|
|
195
|
+
return $formatted;
|
|
196
|
+
}
|
|
197
|
+
return '-';
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// --- Metin (String) İşleme Fonksiyonları ---
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Uzun metinleri keser ve sonuna ... ekler
|
|
204
|
+
*/
|
|
205
|
+
public static function truncate(string $text, int $length = 100, string $append = '...'): string
|
|
206
|
+
{
|
|
207
|
+
$text = strip_tags($text);
|
|
208
|
+
if (mb_strlen($text, 'UTF-8') <= $length) return $text;
|
|
209
|
+
|
|
210
|
+
$truncated = mb_substr($text, 0, $length, 'UTF-8');
|
|
211
|
+
// Son kelimeyi bölmemek için son boşluğa kadar al
|
|
212
|
+
if (strpos($text, ' ') !== false) {
|
|
213
|
+
$lastSpace = mb_strrpos($truncated, ' ', 0, 'UTF-8');
|
|
214
|
+
if ($lastSpace !== false) {
|
|
215
|
+
$truncated = mb_substr($truncated, 0, $lastSpace, 'UTF-8');
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return $truncated . $append;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// --- Para Birimi Formatlama ---
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Tutar ve para birimi sembolü formatlama
|
|
225
|
+
*/
|
|
226
|
+
public static function money(float $amount, string $currency = 'usd'): string
|
|
227
|
+
{
|
|
228
|
+
$currencies = [
|
|
229
|
+
'usd' => '$', // US Dollar
|
|
230
|
+
'eur' => '€', // Euro
|
|
231
|
+
'try' => '₺', // Turkish Lira
|
|
232
|
+
'tl' => '₺', // Turkish Lira
|
|
233
|
+
'gbp' => '£', // British Pound
|
|
234
|
+
'jpy' => '¥', // Japanese Yen
|
|
235
|
+
'cny' => '¥', // Chinese Yuan
|
|
236
|
+
'rub' => '₽', // Russian Ruble
|
|
237
|
+
'inr' => '₹', // Indian Rupee
|
|
238
|
+
'aud' => 'A$', // Australian Dollar
|
|
239
|
+
'cad' => 'C$', // Canadian Dollar
|
|
240
|
+
'chf' => 'CHF', // Swiss Franc
|
|
241
|
+
'krw' => '₩', // South Korean Won
|
|
242
|
+
'brl' => 'R$', // Brazilian Real
|
|
243
|
+
'zar' => 'R', // South African Rand
|
|
244
|
+
'sek' => 'kr', // Swedish Krona
|
|
245
|
+
'nok' => 'kr', // Norwegian Krone
|
|
246
|
+
'mxn' => '$', // Mexican Peso
|
|
247
|
+
'sgd' => 'S$', // Singapore Dollar
|
|
248
|
+
'hkd' => 'HK$', // Hong Kong Dollar
|
|
249
|
+
'nzd' => 'NZ$', // New Zealand Dollar
|
|
250
|
+
'aed' => 'د.إ', // UAE Dirham
|
|
251
|
+
'sar' => '﷼', // Saudi Riyal
|
|
252
|
+
'pln' => 'zł' // Polish Zloty
|
|
253
|
+
];
|
|
254
|
+
|
|
255
|
+
$currency = strtolower($currency);
|
|
256
|
+
$symbol = $currencies[$currency] ?? strtoupper($currency) . ' ';
|
|
257
|
+
|
|
258
|
+
// Sayıyı 1.250,50 veya 1,250.50 gibi formatlar. Genel standart olarak 1.250,50 (Avrupa/TR)
|
|
259
|
+
// İhtiyaca göre number_format değiştirilebilir. (TR formatı baz alındı)
|
|
260
|
+
$formattedAmount = number_format($amount, 2, ',', '.');
|
|
261
|
+
|
|
262
|
+
// USD ve GBP gibi birimlerde sembol genelde başa gelir, TL veya EUR'da sona.
|
|
263
|
+
if (in_array($currency, ['usd', 'gbp', 'aud', 'cad', 'sgd', 'hkd', 'nzd', 'mxn', 'brl'])) {
|
|
264
|
+
return $symbol . $formattedAmount;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return $formattedAmount . ' ' . $symbol;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Geliştiriciler (Özellikle Juniorlar) için kullanımı en kolay global yardımcı fonksiyonlar
|
|
272
|
+
if (!function_exists('display')) {
|
|
273
|
+
function display($data, string $default = ''): string {
|
|
274
|
+
return \Bin\ViewMethod::display($data, $default);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (!function_exists('escapeUrl')) {
|
|
279
|
+
function escapeUrl(string $url): string {
|
|
280
|
+
return \Bin\ViewMethod::escapeUrl($url);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (!function_exists('formatDate')) {
|
|
285
|
+
function formatDate(?string $date, string $format = 'd.m.Y H:i'): string {
|
|
286
|
+
return \Bin\ViewMethod::formatDate($date, $format);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (!function_exists('csrfField')) {
|
|
291
|
+
function csrfField(): string {
|
|
292
|
+
return \Bin\ViewMethod::csrfField();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (!function_exists('day')) {
|
|
297
|
+
function day($date): string {
|
|
298
|
+
return \Bin\ViewMethod::day($date);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (!function_exists('month')) {
|
|
303
|
+
function month($date): string {
|
|
304
|
+
return \Bin\ViewMethod::month($date);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (!function_exists('year')) {
|
|
309
|
+
function year($date): string {
|
|
310
|
+
return \Bin\ViewMethod::year($date);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (!function_exists('timeOnly')) {
|
|
315
|
+
function timeOnly($date): string {
|
|
316
|
+
return \Bin\ViewMethod::timeOnly($date);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (!function_exists('fulldate')) {
|
|
321
|
+
function fulldate($date): string {
|
|
322
|
+
return \Bin\ViewMethod::fulldate($date);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (!function_exists('monthName')) {
|
|
327
|
+
function monthName($date, string $lang = 'tr'): string {
|
|
328
|
+
return \Bin\ViewMethod::monthName($date, $lang);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (!function_exists('fulldateName')) {
|
|
333
|
+
function fulldateName($date, string $lang = 'tr'): string {
|
|
334
|
+
return \Bin\ViewMethod::fulldateName($date, $lang);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (!function_exists('timeAgo')) {
|
|
339
|
+
function timeAgo($date, string $lang = 'tr'): string {
|
|
340
|
+
return \Bin\ViewMethod::timeAgo($date, $lang);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (!function_exists('truncate')) {
|
|
345
|
+
function truncate(string $text, int $length = 100, string $append = '...'): string {
|
|
346
|
+
return \Bin\ViewMethod::truncate($text, $length, $append);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (!function_exists('money')) {
|
|
351
|
+
function money(float $amount, string $currency = 'usd'): string {
|
|
352
|
+
return \Bin\ViewMethod::money($amount, $currency);
|
|
353
|
+
}
|
|
354
|
+
}
|