RESAZIP-PC\resaz

update

...@@ -90,3 +90,62 @@ extension=gmp ...@@ -90,3 +90,62 @@ extension=gmp
90 extension=bcmath 90 extension=bcmath
91 # 3) Restart web server / PHP-FPM service 91 # 3) Restart web server / PHP-FPM service
92 ``` 92 ```
93 +
94 +## QueryLog (Laravel shared package)
95 +
96 +### 1) Publish config in child project
97 +```bash
98 +php artisan vendor:publish --tag=query-log-config
99 +```
100 +
101 +This creates `config/query_log.php` so each project can tune its own settings.
102 +
103 +### 2) Publish migration in child project
104 +```bash
105 +php artisan vendor:publish --tag=query-log-migrations
106 +php artisan migrate
107 +```
108 +
109 +This publishes a production-oriented migration for `log_queries` with key indexes:
110 +
111 +- `query_at`
112 +- `query_type`
113 +- `connection`
114 +- `user_id`
115 +- composite indexes for common filter windows
116 +
117 +### 3) Minimal table fields
118 +
119 +Use your own migration and ensure these columns exist in the configured table (`query_log.table`):
120 +
121 +- `action` (string)
122 +- `query` (longText/text)
123 +- `query_type` (string, example: `insert`, `update`, `delete`, `replace`)
124 +- `query_time` (float/double)
125 +- `query_at` (datetime)
126 +- `query_order` (int)
127 +- `connection` (string)
128 +- `ip` (nullable string)
129 +- `user_id` (nullable string/int)
130 +- `is_screen` (tinyint/bool)
131 +
132 +### 4) Important config for production
133 +
134 +- `enable`: enable/disable query log
135 +- `min_time`: skip very fast queries (ms)
136 +- `sample_rate`: sampling percent (`0-100`) to reduce high-traffic load
137 +- `chunk`: batch size per queue job
138 +- `max_queries_per_request`: hard limit per request
139 +- `skip_route_patterns`: wildcard route/url patterns to skip
140 +- `skip_command_patterns`: wildcard console command patterns to skip
141 +- `mask_sensitive_bindings`: mask sensitive values in SQL bindings
142 +- `sensitive_keywords`: keyword list used for masking
143 +- `masked_value`: replacement text for sensitive bindings
144 +
145 +### 5) Behavior highlights
146 +
147 +- Query buffer is separated by DB connection.
148 +- Buffer is flushed when transaction commits (outermost level).
149 +- Buffer is cleared on rollback (rolled-back queries are not logged).
150 +- Write-query detection supports CTE (`WITH ... UPDATE/INSERT/...`) and skips read queries.
151 +- `query_type` stores action text directly (`insert`, `update`, `delete`, `replace`, `upsert`).
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -10,10 +10,18 @@ ...@@ -10,10 +10,18 @@
10 "require": { 10 "require": {
11 "brick/math": "^0.9 || ^0.10 || ^0.11 || ^0.13", 11 "brick/math": "^0.9 || ^0.10 || ^0.11 || ^0.13",
12 "php": "^7.3 || ^8.0", 12 "php": "^7.3 || ^8.0",
13 - "laravel/framework": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0" 13 + "laravel/framework": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0",
14 + "milon/barcode": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0"
14 }, 15 },
15 "suggest": { 16 "suggest": {
16 "ext-gmp": "Faster big-number calculations", 17 "ext-gmp": "Faster big-number calculations",
17 "ext-bcmath": "Faster decimal calculations when GMP is unavailable" 18 "ext-bcmath": "Faster decimal calculations when GMP is unavailable"
19 + },
20 + "extra": {
21 + "laravel": {
22 + "providers": [
23 + "Daito\\Lib\\QueryLog\\Providers\\QueryLogProvider"
24 + ]
25 + }
18 } 26 }
19 } 27 }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
4 "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 4 "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 "This file is @generated automatically" 5 "This file is @generated automatically"
6 ], 6 ],
7 - "content-hash": "0c23b9705a5fe293b678d1bbc5020207", 7 + "content-hash": "94cb3df5cd945ab2de60f59263dbd8d6",
8 "packages": [ 8 "packages": [
9 { 9 {
10 "name": "brick/math", 10 "name": "brick/math",
...@@ -1144,6 +1144,81 @@ ...@@ -1144,6 +1144,81 @@
1144 "time": "2024-09-21T08:32:55+00:00" 1144 "time": "2024-09-21T08:32:55+00:00"
1145 }, 1145 },
1146 { 1146 {
1147 + "name": "milon/barcode",
1148 + "version": "v12.1.0",
1149 + "source": {
1150 + "type": "git",
1151 + "url": "https://github.com/milon/barcode.git",
1152 + "reference": "052e601665cfb99e119a630b6116fab0eb30183e"
1153 + },
1154 + "dist": {
1155 + "type": "zip",
1156 + "url": "https://api.github.com/repos/milon/barcode/zipball/052e601665cfb99e119a630b6116fab0eb30183e",
1157 + "reference": "052e601665cfb99e119a630b6116fab0eb30183e",
1158 + "shasum": ""
1159 + },
1160 + "require": {
1161 + "ext-gd": "*",
1162 + "illuminate/support": "^7.0|^8.0|^9.0|^10.0 | ^11.0 | ^12.0",
1163 + "php": "^7.3 | ^8.0"
1164 + },
1165 + "type": "library",
1166 + "extra": {
1167 + "laravel": {
1168 + "aliases": {
1169 + "DNS1D": "Milon\\Barcode\\Facades\\DNS1DFacade",
1170 + "DNS2D": "Milon\\Barcode\\Facades\\DNS2DFacade"
1171 + },
1172 + "providers": [
1173 + "Milon\\Barcode\\BarcodeServiceProvider"
1174 + ]
1175 + }
1176 + },
1177 + "autoload": {
1178 + "psr-0": {
1179 + "Milon\\Barcode": "src/"
1180 + }
1181 + },
1182 + "notification-url": "https://packagist.org/downloads/",
1183 + "license": [
1184 + "LGPL-3.0"
1185 + ],
1186 + "authors": [
1187 + {
1188 + "name": "Nuruzzaman Milon",
1189 + "email": "contact@milon.im"
1190 + }
1191 + ],
1192 + "description": "Barcode generator like Qr Code, PDF417, C39, C39+, C39E, C39E+, C93, S25, S25+, I25, I25+, C128, C128A, C128B, C128C, 2-Digits UPC-Based Extention, 5-Digits UPC-Based Extention, EAN 8, EAN 13, UPC-A, UPC-E, MSI (Variation of Plessey code)",
1193 + "keywords": [
1194 + "CODABAR",
1195 + "CODE 128",
1196 + "CODE 39",
1197 + "barcode",
1198 + "datamatrix",
1199 + "ean",
1200 + "laravel",
1201 + "pdf417",
1202 + "qr code",
1203 + "qrcode"
1204 + ],
1205 + "support": {
1206 + "issues": "https://github.com/milon/barcode/issues",
1207 + "source": "https://github.com/milon/barcode/tree/v12.1.0"
1208 + },
1209 + "funding": [
1210 + {
1211 + "url": "https://paypal.me/nuruzzamanmilon",
1212 + "type": "custom"
1213 + },
1214 + {
1215 + "url": "https://github.com/milon",
1216 + "type": "github"
1217 + }
1218 + ],
1219 + "time": "2026-02-07T00:42:12+00:00"
1220 + },
1221 + {
1147 "name": "monolog/monolog", 1222 "name": "monolog/monolog",
1148 "version": "2.11.0", 1223 "version": "2.11.0",
1149 "source": { 1224 "source": {
......
1 +<?php
2 +namespace Daito\Lib;
3 +
4 +use Milon\Barcode\DNS1D;
5 +use Milon\Barcode\DNS2D;
6 +
7 +class DaitoBarcode {
8 + public static function getJan13Number($jan12)
9 + {
10 + // Kiểm tra định dạng
11 + if (!preg_match('/^\d{12}$/', $jan12)) {
12 + return $jan12;
13 + }
14 +
15 + $sum = 0;
16 + for ($i = 0; $i < 12; $i++) {
17 + $digit = (int) $jan12[$i];
18 + $sum += $i % 2 === 0 ? $digit : $digit * 3;
19 + }
20 +
21 + $checkDigit = (10 - ($sum % 10)) % 10;
22 +
23 + return $jan12 . $checkDigit;
24 + }
25 + public static function isJanEAN13($jan)
26 + {
27 + if (!preg_match('/^\d{13}$/', $jan)) {
28 + return false;
29 + }
30 +
31 + $jan12 = substr($jan, 0, 12);
32 + $ean13Jan = self::getJan13Number($jan12);
33 + return $ean13Jan === $jan;
34 + }
35 +
36 + public static function getJan8Number($jan7)
37 + {
38 + if (!preg_match('/^\d{7}$/', $jan7)) {
39 + return $jan7;
40 + }
41 +
42 + $sum = 0;
43 + for ($i = 0; $i < 7; $i++) {
44 + $digit = (int) $jan7[$i];
45 + $sum += $i % 2 === 0 ? $digit * 3 : $digit;
46 + }
47 +
48 + $checkDigit = (10 - ($sum % 10)) % 10;
49 +
50 + return $jan7 . $checkDigit;
51 + }
52 +
53 + public static function isJanEAN8($jan)
54 + {
55 + if (!preg_match('/^\d{8}$/', $jan)) {
56 + return false;
57 + }
58 +
59 + $jan7 = substr($jan, 0, 7);
60 + $ean8Jan = self::getJan8Number($jan7);
61 +
62 + return $ean8Jan === $jan;
63 + }
64 +
65 + public static function getBarcodeTypeJan($jan)
66 + {
67 + if (self::isJanEAN8($jan)) {
68 + return 'EAN8';
69 + }
70 +
71 + if (self::isJanEAN13($jan)) {
72 + return 'EAN13';
73 + }
74 +
75 + return 'C128';
76 + }
77 +
78 + public static function generateBarcodeJan($jan)
79 + {
80 + $typeJan = self::getBarcodeTypeJan($jan);
81 +
82 + if ($typeJan === 'EAN13') {
83 + $jan = substr($jan, 0, 12);
84 + } elseif ($typeJan === 'EAN8') {
85 + $jan = substr($jan, 0, 7);
86 + }
87 +
88 + $dns1d = new DNS1D();
89 +
90 + return $dns1d->getBarcodePNG($jan, $typeJan);
91 + }
92 +
93 + public static function generateBarcodeC128($text)
94 + {
95 + $dns1d = new DNS1D();
96 +
97 + return $dns1d->getBarcodePNG($text, 'C128');
98 + }
99 +
100 + public static function generateBarcodeC39($text)
101 + {
102 + $dns1d = new DNS1D();
103 +
104 + return $dns1d->getBarcodePNG($text, 'C39');
105 + }
106 +
107 + public static function generateBarcodeEAN13($ean13)
108 + {
109 + $dns1d = new DNS1D();
110 +
111 + return $dns1d->getBarcodePNG($ean13, 'EAN13');
112 + }
113 +
114 + public static function generateBarcodeEAN8($ean8)
115 + {
116 + $dns1d = new DNS1D();
117 +
118 + return $dns1d->getBarcodePNG($ean8, 'EAN8');
119 + }
120 +
121 + public static function generateBarcodeQrCode($text)
122 + {
123 + $dns2d = new DNS2D();
124 +
125 + return $dns2d->getBarcodePNG($text, 'QRCODE');
126 + }
127 +}
...\ No newline at end of file ...\ No newline at end of file
1 +<?php
2 +
3 +namespace Daito\Lib;
4 +
5 +use Brick\Math\BigDecimal;
6 +use Brick\Math\RoundingMode;
7 +use RuntimeException;
8 +
9 +class DaitoNumber
10 +{
11 + const DEFAULT_MAX_DECIMALS = 12;
12 +
13 + /**
14 + * Format number with configurable separators, prefix/suffix, and decimal behavior.
15 + *
16 + * Example:
17 + * DaitoNumber::format('1234567.00') => '1,234,567'
18 + * DaitoNumber::format('1234567.5', array('decimals' => 2)) => '1,234,567.50'
19 + */
20 + public static function format($number, array $arrOptions = array())
21 + {
22 + $arrConfig = array_merge(
23 + array(
24 + 'thousands_separator' => ',',
25 + 'decimal_separator' => '.',
26 + 'prefix' => '',
27 + 'suffix' => '',
28 + 'decimals' => null,
29 + 'trim_trailing_zeros' => true,
30 + 'max_decimals' => self::DEFAULT_MAX_DECIMALS,
31 + ),
32 + $arrOptions
33 + );
34 +
35 + $numberString = self::toCanonicalString($number);
36 + $isNegative = strpos($numberString, '-') === 0;
37 + $unsigned = $isNegative ? substr($numberString, 1) : $numberString;
38 +
39 + if ($arrConfig['decimals'] !== null) {
40 + $decimals = (int) $arrConfig['decimals'];
41 + if ($decimals < 0) {
42 + throw new RuntimeException('decimals must be greater than or equal to 0.');
43 + }
44 +
45 + $unsigned = (string) BigDecimal::of($unsigned)->toScale($decimals, RoundingMode::HALF_UP);
46 + } else {
47 + $maxDecimals = (int) $arrConfig['max_decimals'];
48 + if ($maxDecimals < 0) {
49 + throw new RuntimeException('max_decimals must be greater than or equal to 0.');
50 + }
51 +
52 + $unsigned = (string) BigDecimal::of($unsigned)->toScale($maxDecimals, RoundingMode::HALF_UP);
53 + if ($arrConfig['trim_trailing_zeros']) {
54 + $unsigned = self::trimTrailingZeros($unsigned);
55 + }
56 + }
57 +
58 + $arrParts = explode('.', $unsigned, 2);
59 + $integerPart = self::addThousandsSeparator($arrParts[0], (string) $arrConfig['thousands_separator']);
60 + $decimalPart = isset($arrParts[1]) ? $arrParts[1] : '';
61 +
62 + $formattedNumber = $integerPart;
63 + if ($decimalPart !== '') {
64 + $formattedNumber .= (string) $arrConfig['decimal_separator'] . $decimalPart;
65 + }
66 +
67 + $formatted = (string) $arrConfig['prefix'] . $formattedNumber . (string) $arrConfig['suffix'];
68 +
69 + return $isNegative ? '-' . $formatted : $formatted;
70 + }
71 +
72 + /**
73 + * Format currency-friendly output (default 2 decimals, keep trailing zeros).
74 + *
75 + * Example:
76 + * DaitoNumber::formatCurrency('1234.5') => '1,234.50'
77 + * DaitoNumber::formatCurrency('1234.5', array('prefix' => '$')) => '$1,234.50'
78 + */
79 + public static function formatCurrency($number, array $arrOptions = array())
80 + {
81 + $arrCurrencyOptions = array_merge(
82 + array(
83 + 'decimals' => 2,
84 + 'trim_trailing_zeros' => false,
85 + 'prefix' => '',
86 + 'suffix' => '',
87 + ),
88 + $arrOptions
89 + );
90 +
91 + return self::format($number, $arrCurrencyOptions);
92 + }
93 +
94 + /**
95 + * Format percentage value.
96 + *
97 + * Example:
98 + * DaitoNumber::formatPercent('12.3456') => '12.35%'
99 + * DaitoNumber::formatPercent('0.1234', array('input_ratio' => true)) => '12.34%'
100 + */
101 + public static function formatPercent($number, array $arrOptions = array())
102 + {
103 + $arrPercentOptions = array_merge(
104 + array(
105 + 'decimals' => 2,
106 + 'trim_trailing_zeros' => true,
107 + 'suffix' => '%',
108 + 'input_ratio' => false,
109 + ),
110 + $arrOptions
111 + );
112 +
113 + $numberValue = $number;
114 + if ($arrPercentOptions['input_ratio']) {
115 + $numberValue = (string) BigDecimal::of(self::toCanonicalString($number))->multipliedBy('100');
116 + }
117 +
118 + unset($arrPercentOptions['input_ratio']);
119 +
120 + return self::format($numberValue, $arrPercentOptions);
121 + }
122 +
123 + private static function toCanonicalString($number)
124 + {
125 + if (is_int($number) || is_string($number)) {
126 + $numberString = trim((string) $number);
127 + } elseif (is_float($number)) {
128 + $numberString = self::trimTrailingZeros(sprintf('%.14F', $number));
129 + } else {
130 + throw new RuntimeException('DaitoNumber only supports int, float, or numeric string.');
131 + }
132 +
133 + if ($numberString === '' || !preg_match('/^[+-]?\d+(\.\d+)?$/', $numberString)) {
134 + throw new RuntimeException('Invalid number format.');
135 + }
136 +
137 + return (string) BigDecimal::of($numberString);
138 + }
139 +
140 + private static function addThousandsSeparator($integerPart, $thousandsSeparator)
141 + {
142 + return preg_replace('/\B(?=(\d{3})+(?!\d))/', $thousandsSeparator, $integerPart);
143 + }
144 +
145 + private static function trimTrailingZeros($numberString)
146 + {
147 + if (strpos($numberString, '.') === false) {
148 + return $numberString;
149 + }
150 +
151 + $numberString = rtrim($numberString, '0');
152 + $numberString = rtrim($numberString, '.');
153 +
154 + return $numberString === '' ? '0' : $numberString;
155 + }
156 +}
1 <?php 1 <?php
2 +
2 namespace Daito\Lib; 3 namespace Daito\Lib;
3 4
4 -class DaitoString { 5 +use RuntimeException;
5 - public static function toUpper($text){ 6 +
6 - return strtoupper($text); 7 +class DaitoString
8 +{
9 + const UTF8 = 'UTF-8';
10 + const NKF_SOURCE_ENCODINGS = 'SJIS-win,CP932,Shift_JIS,EUC-JP,UTF-8';
11 +
12 + /**
13 + * Collapse multiple spaces/tabs/newlines into a single ASCII space.
14 + *
15 + * Example:
16 + * DaitoString::collapseSpaces("a b\t\tc") => "a b c"
17 + */
18 + public static function collapseSpaces($input)
19 + {
20 + return preg_replace('/\s+/u', ' ', (string) $input);
21 + }
22 +
23 + /**
24 + * Convert full-width Japanese spaces to ASCII spaces.
25 + *
26 + * Example:
27 + * DaitoString::normalizeFullWidthSpace("A B") => "A B"
28 + */
29 + public static function normalizeFullWidthSpace($input)
30 + {
31 + return str_replace(' ', ' ', (string) $input);
32 + }
33 +
34 + /**
35 + * Convert half-width kana to full-width kana.
36 + *
37 + * Example:
38 + * DaitoString::toFullWidthKana("カタカナ") => "カタカナ"
39 + */
40 + public static function toFullWidthKana($text)
41 + {
42 + return mb_convert_kana((string) $text, 'KV', self::UTF8);
43 + }
44 +
45 + /**
46 + * Convert full-width kana to half-width kana.
47 + *
48 + * Example:
49 + * DaitoString::toHalfWidthKana("カタカナ") => "カタカナ"
50 + */
51 + public static function toHalfWidthKana($text)
52 + {
53 + return mb_convert_kana((string) $text, 'kV', self::UTF8);
54 + }
55 +
56 + /**
57 + * Split text by normalized spaces (full-width/extra spaces are handled).
58 + *
59 + * Example:
60 + * DaitoString::splitBySpace("A  B C") => array("A", "B", "C")
61 + */
62 + public static function splitBySpace($string)
63 + {
64 + $normalized = self::normalizeFullWidthSpace((string) $string);
65 + $normalized = trim(self::collapseSpaces($normalized));
66 +
67 + if ($normalized === '') {
68 + return array();
69 + }
70 +
71 + return explode(' ', $normalized);
72 + }
73 +
74 + /**
75 + * Convert Hiragana to Katakana.
76 + *
77 + * Example:
78 + * DaitoString::toKatakana("ひらがな") => "ヒラガナ"
79 + */
80 + public static function toKatakana($input)
81 + {
82 + return mb_convert_kana((string) $input, 'C', self::UTF8);
83 + }
84 +
85 + /**
86 + * Check whether the input contains Japanese characters.
87 + *
88 + * Example:
89 + * DaitoString::isJapanese("abc日本語") => true
90 + * DaitoString::isJapanese("abcdef") => false
91 + */
92 + public static function isJapanese($input)
93 + {
94 + return preg_match('/[\x{3040}-\x{30FF}\x{3400}-\x{4DBF}\x{4E00}-\x{9FFF}\x{FF66}-\x{FF9D}]/u', (string) $input) === 1;
95 + }
96 +
97 + /**
98 + * Convert Japanese-encoded text file to UTF-8.
99 + * Prefer nkf when available, fallback to mb_convert_encoding.
100 + *
101 + * Example:
102 + * DaitoString::convertToUtf8('/tmp/source.csv');
103 + * DaitoString::convertToUtf8('/tmp/source.csv', '/tmp/out', 'source_utf8.csv', 1);
104 + */
105 + public static function convertToUtf8($sourceFile, $destDir = '', $fileName = '', $isBk = 0)
106 + {
107 + $sourceFilePath = (string) $sourceFile;
108 + if (!is_file($sourceFilePath)) {
109 + throw new RuntimeException('Source file does not exist: ' . $sourceFilePath);
110 + }
111 +
112 + $targetDirectory = $destDir ? (string) $destDir : dirname($sourceFilePath);
113 + if (!is_dir($targetDirectory)) {
114 + throw new RuntimeException('Destination directory does not exist: ' . $targetDirectory);
115 + }
116 +
117 + $targetFileName = $fileName ? (string) $fileName : basename($sourceFilePath);
118 + $destFile = $targetDirectory . DIRECTORY_SEPARATOR . $targetFileName;
119 +
120 + if ((string) realpath($sourceFilePath) === (string) realpath($destFile)) {
121 + $destFile .= '_' . time();
122 + }
123 +
124 + if ($isBk) {
125 + $backupFile = $targetDirectory . DIRECTORY_SEPARATOR . $targetFileName . '.bak';
126 + if (!copy($sourceFilePath, $backupFile)) {
127 + throw new RuntimeException('Can not create backup file: ' . $backupFile);
7 } 128 }
8 - public static function toLower($text){ 129 + }
9 - return strtolower($text); 130 +
131 + $utf8Content = self::convertJapaneseTextToUtf8($sourceFilePath);
132 + if (file_put_contents($destFile, $utf8Content) === false) {
133 + throw new RuntimeException('Can not write destination file: ' . $destFile);
134 + }
135 +
136 + return $destFile;
137 + }
138 +
139 + private static function convertJapaneseTextToUtf8($sourceFilePath)
140 + {
141 + if (self::canUseNkf()) {
142 + $nkfContent = self::convertFileByNkf($sourceFilePath);
143 + if ($nkfContent !== null) {
144 + return $nkfContent;
145 + }
146 + }
147 +
148 + return self::convertFileToUtf8ByMbstring($sourceFilePath);
149 + }
150 +
151 + private static function canUseNkf()
152 + {
153 + if (!function_exists('shell_exec')) {
154 + return false;
155 + }
156 +
157 + $disabledFunctions = (string) ini_get('disable_functions');
158 + if ($disabledFunctions !== '' && strpos($disabledFunctions, 'shell_exec') !== false) {
159 + return false;
160 + }
161 +
162 + $output = @shell_exec('nkf --version');
163 +
164 + return is_string($output) && $output !== '';
165 + }
166 +
167 + private static function convertFileByNkf($sourceFilePath)
168 + {
169 + $command = 'nkf -w -- ' . escapeshellarg($sourceFilePath);
170 + $output = @shell_exec($command);
171 +
172 + return is_string($output) ? $output : null;
173 + }
174 +
175 + /**
176 + * Convert a file content to UTF-8 using mbstring.
177 + *
178 + * Example:
179 + * DaitoString::convertFileToUtf8ByMbstring('/tmp/source_sjis.txt');
180 + */
181 + public static function convertFileToUtf8ByMbstring($sourceFilePath)
182 + {
183 + $content = file_get_contents($sourceFilePath);
184 + if ($content === false) {
185 + throw new RuntimeException('Can not read source file: ' . $sourceFilePath);
186 + }
187 +
188 + return self::convertTextToUtf8ByMbstring($content);
189 + }
190 +
191 + /**
192 + * Convert raw text to UTF-8 using mbstring.
193 + *
194 + * Example:
195 + * DaitoString::convertTextToUtf8ByMbstring($rawText);
196 + */
197 + public static function convertTextToUtf8ByMbstring($text)
198 + {
199 + $utf8Content = mb_convert_encoding((string) $text, self::UTF8, self::NKF_SOURCE_ENCODINGS);
200 + if ($utf8Content === false) {
201 + throw new RuntimeException('Can not convert text to UTF-8.');
202 + }
203 +
204 + return $utf8Content;
10 } 205 }
11 } 206 }
...\ No newline at end of file ...\ No newline at end of file
......
1 +<?php
2 +
3 +namespace Daito\Lib\QueryLog\Jobs;
4 +
5 +use Illuminate\Contracts\Queue\ShouldQueue;
6 +use Illuminate\Bus\Queueable;
7 +use Illuminate\Foundation\Bus\Dispatchable;
8 +use Illuminate\Queue\InteractsWithQueue;
9 +use Illuminate\Queue\SerializesModels;
10 +use Illuminate\Support\Facades\DB;
11 +
12 +class SaveQueryLogJob implements ShouldQueue
13 +{
14 + use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
15 +
16 + protected $arrQueries;
17 +
18 + public function __construct(array $arrQueries)
19 + {
20 + $this->arrQueries = $arrQueries;
21 + }
22 +
23 + public function handle(): void
24 + {
25 + if ($this->arrQueries === array()) {
26 + return;
27 + }
28 +
29 + DB::connection(config('query_log.connection', 'query_log'))
30 + ->table(config('query_log.table', 'log_queries'))
31 + ->insert($this->arrQueries);
32 + }
33 +}
1 +<?php
2 +
3 +namespace Daito\Lib\QueryLog\Models;
4 +
5 +use Illuminate\Database\Eloquent\Model;
6 +
7 +class QueryLog extends Model
8 +{
9 + /**
10 + * The table associated with the model.
11 + *
12 + * @var string
13 + */
14 + protected $table = 'log_queries';
15 +
16 + /**
17 + * The primary key for the model.
18 + *
19 + * @var string
20 + */
21 + protected $primaryKey = 'id';
22 +
23 + /**
24 + * Indicates if the IDs are auto-incrementing.
25 + *
26 + * @var bool
27 + */
28 + public $incrementing = true;
29 +
30 + /**
31 + * Indicates if the IDs are auto-incrementing.
32 + *
33 + * @var bool
34 + */
35 + public $timestamps = false;
36 +
37 + /**
38 + * The attributes that are mass assignable.
39 + *
40 + * @var array<int, string>
41 + */
42 + protected $fillable = [
43 + 'action',
44 + 'query',
45 + 'query_type',
46 + 'query_time',
47 + 'query_at',
48 + 'query_order',
49 + 'connection',
50 + 'ip',
51 + 'user_id',
52 + 'is_screen',
53 + ];
54 + protected $connection = 'query_log';
55 +
56 + public function __construct(array $arrAttributes = array())
57 + {
58 + parent::__construct($arrAttributes);
59 +
60 + $this->setConnection(config('query_log.connection', 'query_log'));
61 + $this->setTable(config('query_log.table', 'log_queries'));
62 + }
63 +}
1 +<?php
2 +return [
3 + 'enable' => env('ENABLE_QUERY_LOG', false),
4 + 'log_on_console' => env('QUERY_LOG_ON_CONSOLE', false),
5 + 'sample_rate' => env('QUERY_LOG_SAMPLE_RATE', 100), // 0-100 (%)
6 + 'chunk' => env('QUERY_LOG_CHUNK', 200),
7 + 'max_queries_per_request' => env('QUERY_LOG_MAX_PER_REQUEST', 1000),
8 + 'min_time' => env('QUERY_LOG_MIN_TIME', 0),
9 + 'connection' => env('QUERY_LOG_CONNECTION', 'query_log'),
10 + 'table' => env('QUERY_LOG_TABLE', 'log_queries'),
11 + 'queue_connection' => env('QUERY_LOG_QUEUE_CONNECTION', null),
12 + 'queue_name' => env('QUERY_LOG_QUEUE_NAME', null),
13 + 'max_sql_length' => env('QUERY_LOG_MAX_SQL_LENGTH', 4000),
14 + 'mask_sensitive_bindings' => env('QUERY_LOG_MASK_SENSITIVE_BINDINGS', true),
15 + 'sensitive_keywords' => array(
16 + 'password',
17 + 'passwd',
18 + 'pwd',
19 + 'token',
20 + 'secret',
21 + 'api_key',
22 + 'apikey',
23 + 'authorization',
24 + 'cookie',
25 + 'credit_card',
26 + 'card_number',
27 + 'cvv',
28 + 'pin',
29 + ),
30 + 'masked_value' => '***',
31 + 'skip_route_patterns' => array(
32 + 'horizon*',
33 + 'telescope*',
34 + '_debugbar*',
35 + ),
36 + 'skip_command_patterns' => array(
37 + 'queue:*',
38 + 'horizon*',
39 + 'schedule:run',
40 + ),
41 + 'ignore_tables' => array(
42 + 'log_queries',
43 + 'jobs',
44 + 'failed_jobs',
45 + 'migrations',
46 + 'mst_batch',
47 + ),
48 +];
1 +<?php
2 +
3 +use Illuminate\Database\Migrations\Migration;
4 +use Illuminate\Database\Schema\Blueprint;
5 +use Illuminate\Support\Facades\Schema;
6 +
7 +return new class extends Migration {
8 + public function up(): void
9 + {
10 + $connection = config('query_log.connection', 'query_log');
11 + $table = config('query_log.table', 'log_queries');
12 +
13 + Schema::connection($connection)->create($table, function (Blueprint $table) {
14 + $table->bigIncrements('id');
15 + $table->string('action', 512)->nullable();
16 + $table->longText('query');
17 + $table->string('query_type', 32);
18 + $table->decimal('query_time', 10, 3)->default(0);
19 + $table->dateTime('query_at');
20 + $table->unsignedInteger('query_order')->default(0);
21 + $table->string('connection', 64)->nullable();
22 + $table->string('ip', 64)->nullable();
23 + $table->string('user_id', 64)->nullable();
24 + $table->boolean('is_screen')->default(false);
25 +
26 + $table->index('query_at', 'idx_log_queries_query_at');
27 + $table->index('query_type', 'idx_log_queries_query_type');
28 + $table->index('connection', 'idx_log_queries_connection');
29 + $table->index('user_id', 'idx_log_queries_user_id');
30 + $table->index(array('query_at', 'query_type'), 'idx_log_queries_at_type');
31 + $table->index(array('connection', 'query_at'), 'idx_log_queries_connection_at');
32 + });
33 + }
34 +
35 + public function down(): void
36 + {
37 + $connection = config('query_log.connection', 'query_log');
38 + $table = config('query_log.table', 'log_queries');
39 +
40 + Schema::connection($connection)->dropIfExists($table);
41 + }
42 +};
1 +<?php
2 +
3 +require __DIR__ . '/vendor/autoload.php';
4 +
5 +$container = new Illuminate\Container\Container();
6 +Illuminate\Container\Container::setInstance($container);
7 +
8 +$container->instance('config', new Illuminate\Config\Repository(array(
9 + 'barcode' => array(
10 + 'store_path' => sys_get_temp_dir(),
11 + ),
12 +)));
13 +
14 +$base64 = Daito\Lib\DaitoBarcode::generateBarcodeQrCode('HELLO-QR');
15 +
16 +echo substr($base64, 0, 80) . PHP_EOL;
17 +echo 'length: ' . strlen($base64) . PHP_EOL;
18 +
19 +echo Daito\Lib\DaitoMath::div(1, 2) . PHP_EOL;
...\ No newline at end of file ...\ No newline at end of file