20 марта 2026 Нет комментариев

ip:

awk '{print $1}' /var/log/httpd/site.ru_access.log | sort | uniq -c | sort -nr | head -20

User-Agent

awk -F\" '{print $6}' /var/log/httpd/site.ru_access.log | sort | uniq -c | sort -nr | head -20
Categories: Linux Tags:
20 марта 2026 Нет комментариев

/site/ready.php

$wire->addHook('ProcessPageAdd::execute', function($event) {
    $process = $event->object;
 
    $event->return .= <<<JS
<script>
document.addEventListener("DOMContentLoaded", function() {
    var form = document.querySelector('form#ProcessPageAdd');
    if(!form) return;
 
    form.addEventListener('submit', function() {
        var titleInput = document.querySelector('input[name="title"]');
        if(titleInput && !titleInput.value) {
            titleInput.value = 'NotPublished';
        }
 
        var nameInput = document.querySelector('input[name="_pw_page_name"]');
        if(nameInput && !nameInput.value) {
            nameInput.value = 'np-' + Math.floor(Date.now() / 1000);
        }
    });
});
</script>
JS;
});

Список статей, например, /site/templates/page-category.php

$allPosts = $pages->find('limit=9, template=blog-post, sort=-publish_from, status=published, category='.$page->id.', title!=NotPublished');

Страница публикации, например, /site/templates/blog-post.php

if($user->language->isDefault() && $page->title == 'NotPublished') {
	throw new Wire404Exception();
}

Список статей в админке, например, /site/templates/template-parts/dashboard/_dashboard_post_page.php

<a href="<?= $blogPost->editUrl() ?>">
	<?php if($blogPost->title == 'NotPublished'): ?>
		<strike><?= $blogPost->title ?></strike>
	<?php else: ?>
		<?= $blogPost->title ?>
	<?php endif;?>
	<?php
		$title_en=$blogPost->getLanguageValue('en', 'title');
		if($title_en!=$blogPost->title){
			echo '<br/>'.$title_en;
		}
	?>
</a>
Categories: PHP, Web Tags:
26 декабря 2025 Нет комментариев

Задача: FlexSlider 2 — при клике на крайний видимый (правый) слайд прокручивать слайдер дальше вправо, как будто нажали стрелку «next», чтобы было понятно, что там есть ещё элементы.

var thumbWidth=function(){
	return(window.innerWidth<480)?80:190;
}
var thumbMargin=function(){
	return(window.innerWidth<480)?10:20;
}
$('#detail_gallery_thumbs').flexslider({
	animation:"slide",
	controlNav:false,
	animationLoop:false,
	slideshow:false,
	itemWidth:thumbWidth(),
	itemMargin:thumbMargin(),
	asNavFor:'#detail_gallery_photos'
});
var slider=$('#detail_gallery_thumbs');
slider.on('click','.slides > li',function(){
	var flex=slider.data('flexslider');
	var index=$(this).index();
	var visibleCount=flex.visible;
	var lastVisibleIndex=flex.currentSlide+visibleCount-1;
	if(index===lastVisibleIndex&&flex.currentSlide+visibleCount<flex.count){
		flex.flexAnimate(flex.currentSlide+1);
	}
});
$('#detail_gallery_photos').flexslider({
	animation:"slide",
	controlNav:false,
	animationLoop:false,
	slideshow:false,
	sync:"#detail_gallery_thumbs"
});
Categories: Javascript Tags:
9 декабря 2025 Нет комментариев

1. Подготовить файлы и sql запросы — скрипт на php (запускать дважды, первый раз файлам устанавливается дата из exif):
$pk=200; — значение должно быть больше текущего максимального в ZGENERICASSET

<?php
ini_set('date.timezone','Etc/GMT-4');
$dir=__DIR__.'/photos';
$files=scandir($dir);
$files=array_diff(scandir($dir),array('.','..'));
usort($files,function($a,$b) use ($dir){
	return filemtime($dir.'/'.$a)<=>filemtime($dir.'/'.$b);
});
$outputFile='insert_photos.sql';
$sql="BEGIN TRANSACTION;\n";
$pk=200;
$z_ent=15;
$z_opt=1;
$sql.="DELETE FROM \"ZGENERICASSET\" WHERE Z_PK>=".$pk.";\n";
$sql.="DELETE FROM \"ZADDITIONALASSETATTRIBUTES\" WHERE Z_PK>=".$pk.";\n";
$sql.="DELETE FROM \"Z_8ASSETS\" WHERE Z_14ASSETS>=".$pk.";\n";
$pk+=100;
foreach($files as $file){
	$path=$dir.'/'.$file;
	$ext=strtolower(pathinfo($file,PATHINFO_EXTENSION));
	$isVideo=($ext==='mov');
	$isImage=($ext==='jpg'||$ext==='jpeg');
	if(!$isVideo&&!$isImage)continue;
	$filename=$file;
	$title=pathinfo($file,PATHINFO_FILENAME);
	$directory='DCIM/100APPLE';
	$zuuid="X'".bin2hex(random_bytes(16))."'";
	if($isImage){
		$width=getimagesize($path)[0];
		$height=getimagesize($path)[1];
		$ZUNIFORMTYPEIDENTIFIER='public.jpeg';
		$orientation=($width>$height)?3:6;
		$add_orientation=$orientation;
		$ZKIND=0;
		$ZHIGHDYNAMICRANGETYPE=1;
		$ZORIGINALHEIGHT=($width>$height)?$height:$width;
		$ZORIGINALWIDTH=($width>$height)?$width:$height;
		$ZDURATION='0.0';
		$exif=@exif_read_data($path);
		if(!empty($exif['DateTimeOriginal'])){
			$shootTimeStr=$exif['DateTimeOriginal'];
		}
		elseif(!empty($exif['CreateDate'])){
			$shootTimeStr=$exif['CreateDate'];
		}
		elseif(!empty($exif['DateTimeDigitized'])){
			$shootTimeStr=$exif['DateTimeDigitized'];
		}
		else{
			$shootTimeStr=null;
		}
		if($shootTimeStr){
			$shootUnix=strtotime(str_replace(':','-',substr($shootTimeStr,0,10)).substr($shootTimeStr,10));
		}
		else{
			$shootUnix=filemtime($path);
		}
	}
	else{
		$width=640;
		$height=480;
		$ZUNIFORMTYPEIDENTIFIER='com.apple.quicktime-movie';
		$orientation=1;
		$add_orientation=0;
		$ZKIND=1;
		$ZHIGHDYNAMICRANGETYPE=null;
		$ZORIGINALHEIGHT=0;
		$ZORIGINALWIDTH=0;
		$ZDURATION='4.0';
		$shootUnix=filemtime($path);
	}
	touch($path,$shootUnix,$shootUnix);
	$macEpoch=strtotime('2001-01-01 00:00:00');
	$macTime=round(($shootUnix-$macEpoch)+(rand(10,99999)/100000),5);
	$originalSize=filesize($path);
	$zgenericasset=[
		'Z_PK'=>$pk,
		'Z_ENT'=>$z_ent,
		'Z_OPT'=>$z_opt,
		'ZCLOUDHASCOMMENTSBYME'=>NULL,
		'ZCLOUDHASCOMMENTSCONVERSATION'=>NULL,
		'ZCLOUDHASUNSEENCOMMENTS'=>NULL,
		'ZCLOUDPLACEHOLDERKIND'=>0,
		'ZCOMPLETE'=>1,
		'ZFLAGGED'=>0,
		'ZHEIGHT'=>$height,
		'ZKIND'=>$ZKIND,
		'ZORIENTATION'=>$orientation,
		'ZSAVEDASSETTYPE'=>3,
		'ZTHUMBNAILINDEX'=>1,
		'ZWIDTH'=>$width,
		'ZADDITIONALATTRIBUTES'=>$pk,
		'ZCLOUDBATCHPUBLISHDATE'=>NULL,
		'ZCLOUDLASTVIEWEDCOMMENTDATE'=>NULL,
		'ZDATECREATED'=>$macTime,
		'ZMODIFICATIONDATE'=>ceil($macTime),
		'ZSORTTOKEN'=>$macTime,
		'ZCLOUDASSETGUID'=>NULL,
		'ZCLOUDASSETKIND'=>NULL,
		'ZCLOUDBATCHID'=>NULL,
		'ZCLOUDCOLLECTIONGUID'=>NULL,
		'ZDIRECTORY'=>$directory,
		'ZFILENAME'=>$filename,
		'ZTITLE'=>$title,
		'ZUNIFORMTYPEIDENTIFIER'=>$ZUNIFORMTYPEIDENTIFIER,
		'ZCLOUDMETADATA'=>NULL,
		'ZFACERECTANGLES'=>NULL,
		'ZUUID'=>$zuuid,
		'ZLOCATIONDATA'=>NULL,
		'ZIMAGEURLDATA'=>NULL,
		'ZTHUMBNAILURLDATA'=>NULL,
	];
	$zadditional=[
		'Z_PK'=>$pk,
		'Z_ENT'=>1,
		'Z_OPT'=>2,
		'ZEMBEDDEDTHUMBNAILHEIGHT'=>0,
		'ZEMBEDDEDTHUMBNAILLENGTH'=>0,
		'ZEMBEDDEDTHUMBNAILOFFSET'=>0,
		'ZEMBEDDEDTHUMBNAILWIDTH'=>0,
		'ZHIGHDYNAMICRANGETYPE'=>$ZHIGHDYNAMICRANGETYPE,
		'ZORIGINALFILESIZE'=>$originalSize,
		'ZORIGINALHEIGHT'=>$ZORIGINALHEIGHT,
		'ZORIGINALORIENTATION'=>$orientation,
		'ZORIGINALWIDTH'=>$ZORIGINALWIDTH,
		'ZASSET'=>$pk,
		'Z14_ASSET'=>15,
		'ZDURATION'=>$ZDURATION,
		'ZCREATORBUNDLEID'=>NULL,
		'ZORIGINALFILENAME'=>$filename,
		'ZORIGINALPATH'=>$directory,
		'ZIMPORTSESSIONID'=>NULL,
		'ZORIGINALASSETSUUID'=>NULL,
	];
	$album=[
		'Z_8ALBUMS'=>4,
		'Z_14ASSETS'=>$pk,
		'Z_FOK_14ASSETS'=>2048,
	];
	$columns=implode(',',array_keys($zgenericasset));
	$values=implode(',',array_map(fn($v)=>is_null($v)?'NULL':(is_numeric($v)?$v:"'$v'"),$zgenericasset));
	$sql.=str_replace("'',NULL","',NULL",str_replace("NULL,'X'","NULL,X'","INSERT INTO \"ZGENERICASSET\"($columns)VALUES($values);"))."\n";
	$columns=implode(',',array_keys($zadditional));
	$values=implode(',',array_map(fn($v)=>is_null($v)?'NULL':(is_numeric($v)?$v:"'$v'"),$zadditional));
	$sql.="INSERT INTO \"ZADDITIONALASSETATTRIBUTES\"($columns)VALUES($values);\n";
	$columns=implode(',',array_keys($album));
	$values=implode(',',array_map(fn($v)=>is_null($v)?'NULL':(is_numeric($v)?$v:"'$v'"),$album));
	$sql.="INSERT INTO \"Z_8ASSETS\"($columns)VALUES($values);\n";
	$pk++;
}
$sql.="UPDATE \"Z_PRIMARYKEY\" SET Z_MAX='".$pk."' WHERE Z_NAME='AdditionalAssetAttributes';\n";
$sql.="UPDATE \"Z_PRIMARYKEY\" SET Z_MAX='".$pk."' WHERE Z_NAME='GenericAsset';\n";
$sql.="COMMIT;\n";
file_put_contents($outputFile,$sql);
echo "SQL file generated: $outputFile\n";
?>

2. В локальную резервную копию через iBackupBot импортировать фото и видео после обработки скриптом в /System Files/CameraRollDomain/Media/DCIM/100APPLE
3. Из локальной резервной копии через iBackupBot экспортировать /System Files/CameraRollDomain/Media/PhotoData/Photos.sqlite
4. В DB Browser for SQLite выполнить подготовленные запросы, записать изменения.
5. В iBackupBot импортировать БД обратно.
6. Восстановить резервную копию через iTunes

Categories: iOS Tags:
9 декабря 2025 Нет комментариев

1. Из локальной резервной копии через iBackupBot экспортировать /System Files/WirelessDomain/Library/CallHistory/call_history.db
2. Подготовить csv для загрузки в формате (выгружено через iPhoneBackupBrowser, важно: в длительности здесь важны только секунды, т.к. это полное кол-во секунд)

"From","To","Start date","Duration"
"Me","+79210000000","2013-03-01 20:00:42","0h 26m 1611s"
"+79210000000","Me","2013-03-02 10:41:52","0h 05m 335s"

3. Подготовить sql запросы — скрипт на php:

<?php
$csvFile='calls.csv';
$outputFile='insert_calls.sql';
$handle=fopen($csvFile,'r');
if(!$handle){
	die("Cannot open CSV file.\n");
}
$sql="BEGIN TRANSACTION;\n";
$header=fgetcsv($handle);
$rowId=1;
ini_set('date.timezone','Etc/GMT-3');
while(($data=fgetcsv($handle))!==false){
	list($from,$to,$startDate,$duration)=$data;
	$from=trim($from,'"');
	$to=trim($to,'"');
	$startDate=trim($startDate,'"');
	$duration=trim($duration,'"');
	preg_match('/(\d+)s$/',$duration,$matches);
	$totalSeconds=isset($matches[1])?intval($matches[1]):0;
	if($from==='Me'){
		$flags=5;
		$address=$to;
	}
	else{
		$flags=4;
		$address=$from;
	}
	$timestamp=strtotime($startDate);
	$mcc='255';
	$mnc='01';
	$sql.="INSERT INTO call VALUES($rowId,'$address',$timestamp,$totalSeconds,$flags,-1,'','$mcc','$mnc',1,0,NULL,NULL);\n";
	$rowId++;
}
$sql.="COMMIT;\n";
fclose($handle);
file_put_contents($outputFile,$sql);
echo "SQL file generated: $outputFile\n";
?>

4. В DB Browser for SQLite выполнить подготовленные запросы, записать изменения.
5. В iBackupBot импортировать БД обратно.
6. Восстановить резервную копию через iTunes

Categories: iOS Tags:
27 ноября 2025 1 комментарий

если установлен squid без OpenSSL полностью удалить

sudo apt remove --purge squid squid-common squid-langpack
sudo apt autoremove
which squid

установить squid с поддержкой OpenSSL

sudo apt install squid-openssl
squid -v | grep -i ssl

создать каталог и самоподписанный CA (корневой сертификат для MITM) для динамической генерации сертификатов под сайты

sudo mkdir -p /etc/squid/ssl
openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 \
	-keyout /etc/squid/ssl/ca.key \
	-out /etc/squid/ssl/ca.crt \
	-subj "/CN=Squid-CA/"
chmod 600 /etc/squid/ssl/ca.key

конфиг

mcedit /etc/squid/squid.conf

на 3128 прокси как было для всех с авторизацией, на 3130 специально для телефона с SSL-bump и без авторизации + MITM (с авторизацией он не может работать)

http_port 3128
auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwords
auth_param basic children 5
auth_param basic realm Proxy Authentication
auth_param basic credentialsttl 2 hours
acl authenticated proxy_auth REQUIRED
http_port 3130 ssl-bump \
	generate-host-certificates=on dynamic_cert_mem_cache_size=4MB \
	cert=/etc/squid/ssl/ca.crt key=/etc/squid/ssl/ca.key
acl iphone_port myport 3130
acl step1 at_step SslBump1
ssl_bump peek step1
ssl_bump bump iphone_port
ssl_bump splice all
http_access allow iphone_port
http_access allow authenticated
http_access deny all
access_log /var/log/squid/access.log
cache_log /var/log/squid/cache.log

пароли для пользователей с авторизацией

htpasswd -c /etc/squid/passwords user
cat /etc/squid/passwords

инициализация SSL DB

security_file_certgen -c -s /var/spool/squid/ssl_db
sudo /usr/lib/squid/security_file_certgen -c -s /var/spool/squid/ssl_db -M 4MB

права

chown proxy:proxy /etc/squid/passwords
chmod 640 /etc/squid/passwords
sudo chown -R proxy:proxy /var/spool/squid
sudo chmod -R 755 /var/spool/squid

перезапуск

squid -k parse
squid -k reconfigure
systemctl restart squid

проверки

systemctl status squid.service
sudo tail -f /var/log/squid/cache.log
sudo tail -f /var/log/squid/access.log

ca.crt установить на iphone, передать, например, с помощью встроенного e-mail клиента
в текущем подключении wi-fi — сервер и порт, без авторизации

Categories: iOS Tags:
30 октября 2024 Нет комментариев
function getSingleIfRepeatedTwiceWithSpace($text){
	if(preg_match('/^(.+)\s\1$/',$text,$matches)){
		return $matches[1];
	}
	return $text;
}
Categories: PHP Tags: