Загрузка файлов, параметр filename в HTTP заголовке Content-Disposition

«Крякозябры» вместо имени файла в IE или ошибка загрузки и сообщение о дублирующемся заголовке на движке WebKit.
if (file_exists($path . '/' . $dfi->hashedName)) {
	$response = new \Http\Response();
	$response->setHeader("X-UA-Compatible", 'IE=edge');
	$response->setHeader("Content-Type", isset($dfi->mimeType) && !$nomime  ? $dfi->mimeType : 'application/octet-stream');
	$response->setHeader("Content-Transfer-Encoding", 'binary');
	$response->setHeader("Content-Disposition", ($nomime ? 'attachment' : 'inline') . '; filename=' . str_replace(['\\','"','#','*',';',':','|','<','>','/','?',','], '_', mb_convert_encoding($dfi->originalName, 'CP1251', 'UTF-8')) . '; filename*=UTF-8\'\''.rawurlencode($dfi->originalName).'');

	$response->setHeader("Content-Length", (string)(filesize($fpath)));
	$response->sendHeaders();
	if ($file = fopen($fpath, 'rb')) {
		while(!feof($file) and (connection_status()==0 || 1)) {
			print(fread($file, 1024*8));
			flush();
		}
		fclose($file);
	}
	exit;
}

Определяем инициатора события (jQuery)

Определить программно вызвано событие $('#elem').trigger('clik') или пользователь «кликнул» по элементу. Варианты:
$( '#elem' ).on('click', function ( e ) {
    if ( e.originalEvent === undefined ) {
        alert( 'triggered programmatically' );   
    } else {
        alert( 'clicked by the user' );   
    }
})

или
$( '#elem' ).on('click', function ( e ) {
    if ( e.isTrigger !== undefined ) {
        alert( 'triggered programmatically' );   
    } else {
        alert( 'clicked by the user' );   
    }
})

или
$( '.elems' ).on('click', function ( e, a ) {
    if ( a !== undefined ) {
        alert( 'triggered programmatically ' + a.from );   
    } else {
        alert( 'clicked by the user' );   
    }
})
$( '#elem' ).trigger('click',{'from':'test'});

Использование переменной окружения .htaccess

cat ./.htaccess
SetEnv APPLICATION_ENV production
AddDefaultCharset UTF-8
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?_url=/$1 [QSA,L]
Используем в php (по умолчанию будет использоваться development):
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV',
              (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
                                         : 'development'));
Вся затея ради того, чтобы использую настройки окружения хоста переключаться между БД разработки и продакшн
public $db_our = '[Metrolog' . (APPLICATION_ENV!='production' ? 'Dev' : '') . '].[dbo].';
И сразу, защитим .htaccess от нечаянного изменений даже в случае наличия рутовых прав, выставим атрибут файлу IMMUTABLE(Неизменяемый) (это для Linux)
# lsattr ./.htaccess
-------------e-- ./.htaccess
# chattr +i ./.htaccess
# lsattr ./.htaccess
----i--------e-- ./.htaccess
(a это для UNIX)
# ls -lo ./.htaccess
-rw-r--r--  1 rianvi  wheel  - 375 Feb 11  2013 ./.htaccess
# chflags schg ./.htaccess
# ls -lo ./.htaccess
-rw-r--r--  1 rianvi  wheel  schg 375 Feb 11  2013 ./.htaccess

Вставка изображения в форму из буфера

Возникла необходимость, вернее, усталость от неудобства. В багтрекер постоянно нужно вставлять скриншоты, и вот как раз сохранение в файл перед прикреплением в форму и достало. Кроссбраузерностью и поддержкой старых версий не заморачивался, в компании повсеместно ИЕ, обновления приходят и устанавливаются постоянно. Сам я предпочитаю Хром. В итоге так и получилось, ИЕ > 9, Хром, ну и Опера, так как она сейчас на ВебКите, Лисицу чинить не стал.
Безымянный51 Безымянный52
В форму добавляю:
<input type="hidden" id="screenshot" name="screenshot" value="">
<div style="margin-top: 20px; position: relative;"> <img id="isimg" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNgYAAAAAMAASsJTYQAAAAASUVORK5CYII="></img> <div id="isforimg" contenteditable="true"> </div> </div>
Стили:
<style>
#isimg {
margin-left: 100px;
padding: 5px;
width: 320px;
height: 220px;
border: none;
background: url(../images/screenshot-grey.png) no-repeat center center;
}
#isforimg {
position: absolute;
padding: 5px;
width: 70px;
height: 70px;
overflow: hidden;
border: 2px solid #eee;
top: -10px;
left: 370px;
text-align: center;
vertical-align: middle;
line-height: 60px;
background: url(../images/klipper.png) no-repeat center center;
}
</style>

На сервере:
if (!empty($_POST['screenshot']) && ($content_pos = strpos($_POST['screenshot'], ';base64,')) && $content_pos!==false) {
try { $filename = md5($issue->getIssueId().'screenshot'.microtime(1)); $file_path = $folderPath.DIRECTORY_SEPARATOR.$filename; $fcontent = base64_decode(substr($_POST['screenshot'], $content_pos + 8)); if (false !== file_put_contents($file_path, $fcontent)) {

И js (без jQuery):

if(document.attachEvent) {
document.attachEvent('paste', onPasteTriggered); // ie < 11
}
else if(document.addEventListener) {
document.addEventListener('paste', onPasteTriggered, false); // google chrome or ie >= 11
}

function onPasteTriggered(e) {

if (e.srcElement.id != 'isforimg')
return;

if (e.clipboardData || e.view.clipboardData) { //google chrome or ie > 9
var copiedData = e.clipboardData ? e.clipboardData.items[0] : e.view.clipboardData.files[0]; //Get the clipboard data

/*if the clipboard data is of type image, read the data*/
if(copiedData && copiedData.type && copiedData.type.indexOf('image') == 0) {

var imageFile = e.clipboardData ? copiedData.getAsFile() : copiedData;

/*HTML5 FileReader API to read the image file*/
var reader = new FileReader();

reader.onload = function (evt) {
var result = evt.target.result; //base64 encoded image
document.getElementById('screenshot').value = result;
document.getElementById('isimg').src = result;
};
reader.readAsDataURL(imageFile);

document.getElementById('isforimg').setAttribute('contenteditable', 'false'); // for IE - for not insert img

setTimeout(function(){document.getElementById('isforimg').setAttribute('contenteditable', 'true');}, 200); //
}
}

setTimeout(function(){ document.getElementById('isforimg').innerHTML = ''; }, 100); //erase what inserted
}



Настроим Exim4 на отправку через smarthost

# dpkg-reconfigure exim4-config
  1. Выбираем «mail sent by smarthost; received via SMTP or fetchmail»
  2. System mail name: «localhost»
  3. IP-addresses to listen on for incoming SMTP connections: «127.0.0.1» — не будем принимать входящие соединения
  4. Other destinations for which mail is accepted: отставляем пустым, можно для всех
  5. Machines to relay mail for: отставляем пустым, можно для всех
  6. IP address or host name of the outgoing smarthost: тут IP-адрес почтовика на который все будем отправлять
  7. Hide local mail name in outgoing mail: NO
  8. Keep number of DNS-queries minimal (Dial-on-Demand): NO — в моем случае нет доступа даже к DNS
  9. Delivery method for local mail: я выбрал «mbox format in /var/mail/»
  10. Split configuration into small files: я выбрал YES

Мелочь

А, редактор vi, сколько лет живу и все не судьба с ним подружиться, стараюсь обходить его стороной. Команда выхода без сохранения :q! Установим более удобный редактор по умолчанию
# export EDITOR='mcedit'
или
# export EDITOR='nano'
и например, редактируем кронтаб crontab -e

Ассоциативный шрифт или транслитерация

Вот давно уже казалось прошла пора руссификаторов и отсутствие кириллицы в наборе символов, а нет, так только кажется. Решил провести эксперимент с выводом русского текста на китайский текстовый LCD. В голову сразу пришло несколько идей. Ограничимся выводом прописных букв без ъ и ё. Вот тестовая панграмма:
В ЧАЩАХ ЮГА ЖИЛ БЫ ЦИТРУС? ДА, НО ФАЛЬШИВЫЙ ЭКЗЕМПЛЯР!
1) Исходная панграмма 2) Транслировать использовать транслитерацию; 3) Использовать МТК2 кодировку; 4) Использовать ассоциативные буквы; 5) Комбинация 2-го и 4-го пункта; 6) Модифицированный вариант пункта 2; 7) Представьте, что человек какие-то буквы не выговаривает, а потом мы это кодируем как в 6-ом пункте.
1. В ЧАЩАХ ЮГА ЖИЛ БЫ ЦИТРУС? ДА, НО ФАЛЬШИВЫЙ ЭКЗЕМПЛЯР!
2. V CHASHAH YUGA ZHIL BY CITRUS? DA, NO FAL'SHIVY' EKZEMPLYAR!
3. W 4AGAH JGA VIL BY CITRUS? DA, NO FALXGIWYJ FKZEMPLQR!
4. B 4AWAX OTA RUA 6B QUTPYC? DA, HO OAABWUBBU JK3EMOAZP!
5. B 4AWAX UGA JIL BY CUTPYC? DA, HO FAL'WUBIY EK3EMPLAP!
6. V 4AWAH UGA JIL BY CITRUS? DA, NO FAL'WIVIY EK3EMPLAR!
7. V 4AHAH UGA JIL BY CITRUS? DA, NO FAL'HIVIY EK3EMPLAR!
Вообще склоняюсь к тому, что если есть поддержка несколько языков на устройстве, добавьте еще один, русский в транслитерации, и будет вам счастье.

RepRapDiscount Smart Controller LCD 2004

Решил проверить экран. Подключил, горит синим и на нем ничего не появляется. Попробовал разные приложения, результат 0. Давай разбираться, а дело оказалось в простой экономии на резисторах. Среднее положение регулятора контрастности на плате не давало даже намека на индикацию.

Тесто

Да, да, именно тесто. Опишу 5 видов замеса, основных 3 — традиционный или короткий, интенсивный и улучшенный. 1. Традиционный или короткий – это замес при минимальных энергозатратах на минимальной скорости, имитирующий старинный ручной замес, когда было очень трудно или почти невозможно ввиду отсутствия чрезмерной физической силы хорошо развить глютен. Поэтому для завершения этого процесса, применяли еще и длительное брожение. Количество дрожжей в тесте минимальное, глютен плохо развит и чтобы это исправить необходимо сделать во время последующего брожения 2-4 опускания. Тесто замешивать достаточно мягкой консистенции. Традиционный замес очень мало окисляет хлебную массу, из-за чего мякиш получается ярко выраженного кремового цвета, клеточная структуру мякиша остается открытой и нерегулярной. 2. Интенсивный замес — длительный интенсивный замес на второй скорости с коротким интервалом брожения. При интенсивном замесе все составляющие вводятся на 1-ой скорости, а оптимальное развитие масса получает уже на 2-ой скорости. Длительный замес настолько насыщает тесто кислородом, что такое окисление доводит цвет мякиша до неправдоподобного белого цвета. Хлеб, сделанный по этой технике, не обладает богатым вкусом, да и черствеет он гораздо быстрее. 3. Замес улучшенный — с одной стороны, решает задачу изготовления как можно больше хлеба, а с другой стороны, позволяет добиться — улучшить вкусовые качества. Все составляющие вносят на 1-ой скорости и, собственно замес, уже производят на 2-ой скорости, но не до полного развития глютена, а только на 3/4. Затем тесто хорошо выбраживают. Из-за относительно небольшого времени замеса, получает мякиш красивого кремового цвета с открытой структурой, благодаря длительному брожению — насыщенный вкус и неплохие сроки хранения. 4. Замес с аутолизом — сперва смешивают два основных компонента т.е. воду и муку в течение 4…5 мин и затем оставляют массу в покое на 15…60 мин, после чего добавляют остальные составляющие и замешивают тесто на второй (быстрой) скорости в течение 12…15 мин. Такой метод избирают чаще всего в том случае, если хотят заметно улучшить показатели муки. 5. Замес двойной гидратации — с большим процентом воды по отношению к муке. При двойной гидратации — часть воды (примерно 60%) вводится в начале замеса и замешивается тесто средней консистенции до хорошего развития глютена. Затем, точнее в конце процесса, вводится оставшаяся водa небольшими порциями. Ну и напоследок, при механическом замесе теста необходимо обращать внимание на базовую температуру. Но про это как нибудь в другой раз.