Премини към съдържанието
Форумът в приложение

По-лесно сърфиране. Научи повече.

Kaldata.com - Форуми

Приложение на форума на цял екран с push известия, значки и други.

За да инсталирате това приложение на iOS и iPadOS
  1. Докоснете Иконата за споделяне в Safari
  2. Превъртете менюто и докоснете Добавяне към началния екран.
  3. Докоснете Добавяне в горния десен ъгъл.
За да инсталирате това приложение на Android
  1. Докоснете менюто с 3 точки (⋮) в горния десен ъгъл на браузъра.
  2. Докоснете Добавяне към началния екран или Инсталиране на приложение.
  3. Потвърдете, като докоснете Инсталиране.

blowfish

Потребител
  • Регистрация

  • Последно онлайн

Всичко публикувано от blowfish

  1. Увод В настоящата статия ще говорим за void указателите в езика C. Забележете – C, а не C++, тъй като указателите оригинално произлизат от C, а поддръжката им в C++ е изцяло наследена от C, и C като цяло е по-добре стандартизиран и по-прост език от C++. Въпреки това, концепциите, техниките и примерите, които ще покажа са почти напълно приложими и в C++. И така, ако вече сте на “ти” с използването на указатели, а термина “void указател” ви звучи странно защото сте се заблудили, че всеки указател трябва да има тип, то тогава е време да научите нещо ново за невероятната гъвкавост която предоставя единствения по рода си език – C. Един по-дълбок поглед върху указателите Сами по себе си, всички указатели, независимо дали са декларирани от тип char *, int *, FILE *, struct mystruct *, mytype_t *, или от който и да е друг вграден или дефиниран от потребителя тип, имат фиксиран размер и на машинно ниво не се различават с нищо по между си. Размерите им са фиксирани, това обикновено е една машинна дума. На практика, в езика C всеки указател е с дължината на int, а int е една машинна дума (с дължина съответно 2/4/8 байта при 16/32/64 битови системи). Мислете за указателите като за нормални числови променливи, със свойството, че числото което съдържат е всъщност адрес в паметта. Сега сигурно се питате: защо в такъв случай указателите изобщо трябва да се декларират с тип? Всъщност, понятието “тип на указател” е една абстракция която показва на компилатора колко байта е дължината на соченият блок от памет (а не на самия указател!), като се започне от указания начален адрес. Когато указателя се “дереференцира”, т.е. извлича се сочената стойност, това има значение защото компилатора трябва да знае точно колко е дължината на сочения блок. Ако ви е трудно да си представите горната картина, разгледайте следното: Паметта всъщност представлява един дълъг масив от байтове, където всеки байт (елемент) има адрес (индекс) и стойността на този байт може да се извлече като се индексира чрез адреса. Както сигурно знаете, един байт съдържа 8 бита, а това прави възможно съществуването на 2^8 = 256 = 0x100 различни стойности вътре. Декларирали сме два указателя, myptr1 и myptr2. Както виждате, независимо че единият сочи към тип short, а другият към mytype, и двата са с дължина 4 байта (зелено оцветените клетки, приемаме 32 битова система). Стойността на всеки един от тези указатели всъщност е число, което представлява начален адрес на блок от паметта, съответно 533 (0x00000215) и 536 (0x00000218). Както всички останали променливи, дори и самите указатели имат адрес в паметта където са разположени – съответно 548 и 543. Приемаме също, че short е с дължина 2 байта, а mytype е потребителски дефиниран тип с дължина 5. От илюстрацията сигурно забелязвате, че единствената операция, заради която указателите трябва да имат тип е операцията “извличане на сочената стойност” или по-краткото “дереференциране”. С други думи, компилатора трябва да покаже на програмата с колко байта нататък от началния адрес да се чете, за да се извлече правилната стойност на променливата. За short това е 2, за mytype е 5 (синьо оцветените клетки). Какво е void указател? Мислете за void указателите като за нормални указатели, с единствената разлика, че не могат да се дереференцират. Те се наричат още указатели от неопределен, общ тип, или “generic pointers”. Те съдържат адрес както всички останали указатели, с разликата, че не показват на компилатора колко байта е дължината на променливата след този адрес. С други думи, ако sizeof(short) е 2, sizeof(mytype) е 5, то sizeof(void) е неопределен. Сега сигурно се питате, защо ми е указател, който не може да се дереференцира? Мощността и гъвкавостта на void указателите идва от факта, че те могат да се преобразуват във всеки един друг тип указател. Като пример, можете да преобразувате void * във short *, mytype *, и т.н. След като вече сте го преобразували, вие може да извлечете сочената стойност. Ето и един богат пример: #include <stdio.h> typedef struct { short a; char b[3]; } mytype; int main (void) { int x = 5; float y = 27.4825; char z = 'K'; mytype myvar = {12345, "ab"}; void *vptr; vptr = &x; /* изкарва “x = 5” */ printf("x = %d\n", *((int *) vptr)); vptr = &y; /* изкарва “y = 27.4825” */ printf("y = %f\n", *((float *) vptr)); vptr = &z; /* изкарва “z = K” */ printf("z = %c\n", *((char *) vptr)); vptr = &myvar; /* изкарва “myvar.a = 12345, myvar.b = ab” */ printf("myvar.a = %d, myvar.b = %s\n", ((mytype *) vptr)->a, ((mytype *) vptr)->b ); return 0; } В горния код имаме четири променливи от различен тип, като последната е от потребителски дефинирания тип mytype. След това декларираме и нашия void указател. Чрез оператора “&” насочваме указателя към началния адрес на съответната променлива. Сега вече vptr сочи на точния начален адрес. Проблема е, че ако искаме да извлечем стойността, към която vptr сочи, не можем да го направим директно, защото компилатора не знае колко байта нататък от първия сочен байт се простира променливата. Затова преобразуваме vptr в съответния тип указател (int *, float *, char *, mytype *), и използваме оператора звезда (или съответно стрелка за структури) за да го дереференцираме. Хитро, нали? Как се използват на практика? Предния код илюстрира много добре какво са void указателите, но на практика е безсмислено да се ползват void указатели (а въобще и указатели) в подобни ситуации. Истинската сила на void указателите идва когато те се ползват като връщани стойности и параметри на функции. Чудили ли сте се например, как е възможно функцията malloc() да връща резултат, който може да се присвои на указател от всякакъв тип? Или как функциите fwrite()/fread() могат да записват/четат блокове от всякакви типове, със всякаква дължина? Тези “чудеса” са възможни именно благодарение на void указателите. Нека разгледаме една функция със следния прототип: int myfunc (void *buf, size_t length) При функция с подобен прототип, C компилатора ще ви позволи да я извикате с указател от какъвто и да е тип, без нужда от преобразуване към void *. При извикване също се очаква да бъде посочена и дължината на блока в байтове, като се започне от началния адрес. Всъщност size_t е дефиниран в стандартния хедър stddef.h като unsigned int, но е широко приета конвенция когато става въпрос за дължина на блок да се ползва size_t. Знаейки началния адрес и дължината на блока, функцията може да го третира байт по байт, без въобще да се интересува от какъв тип е. Ето и как бихме написали функцията: typedef unsigned char ubyte; int myfunc (void *buf, size_t length) { ubyte *p = buf; size_t i = 0; while (i++ < length) { printf(“Byte %d: 0x%02X\n”, i, *p); p++; } return 0; } За да можем да обходим блока байт по байт, декларираме локален за функцията указател и го насочваме към същия адрес, към който сочи и buf, параметъра на функцията. Сега вече p е указател към ubyte, и компилатора знае, че когато той трябва да се дереференцира (операцията *p) или измества (операцията p++), това трябва да стане точно с един байт, тъй като sizeof(unsigned char) = sizeof(ubyte) = 1. По същата логика, указателя p можеше да бъде от тип float * или mytype *, вместо от ubyte *, и тогава функцията щеше да третира блока не като последователност от байтове, а съответно като последователност от числа с плаваща запетая или последователност от структури. Ето как бихме извикали нашата функция: char mystring[] = "test"; mytype mystruct = {12345, "ab"}; short myarray[] = {255, 128, 64, 32}; printf("String:\n"); myfunc(mystring, strlen(mystring)); printf("---\n"); printf("Struct:\n"); myfunc(&mystruct, sizeof(mytype)); printf("---\n"); printf("Array:\n"); myfunc(myarray, 4 * sizeof(short)); printf("---\n"); А ето и какво се извежда: String: Byte 1: 0x74 Byte 2: 0x65 Byte 3: 0x73 Byte 4: 0x74 --- Struct: Byte 1: 0x39 Byte 2: 0x30 Byte 3: 0x61 Byte 4: 0x62 Byte 5: 0x00 Byte 6: 0x24 --- Array: Byte 1: 0xFF Byte 2: 0x00 Byte 3: 0x80 Byte 4: 0x00 Byte 5: 0x40 Byte 6: 0x00 Byte 7: 0x20 Byte 8: 0x00 --- Този подход е изключително полезен когато искате да пишете гъвкави функции, които оперират с паметта независимо от типа, например хеш функции, входно/изходни функции и т.н. Сега, след като надникнахте по-дълбоко в света на указателите, предполагам сте се убедили колко прост е езика C. Всяка променлива се свежда до линейна поредица от байтове и различните типове са просто една абстракция която показва дължината на тази поредица като се започне от началния адрес. Чрез използване на void указатели буквално се научихте как да “цепите” паметта на байтове :-) Очаквайте втора серия или “как да цепим байтовете на битове” използвайки побитовите оператори в C. Засега от мен happy coding, но все пак не се забравяйте по цял ден, излезте малко навън, птички пеят, готино е, и се старайте да не мислите за void указатели поне докато пресичате улицата или шофирате :-) Автор: Благовест Буюклиев, 11.08.2007
  2. Увод Ако сте се занимавали с обработка на текстови данни от формуляри, сигурно вече сте се се сблъсквали с неприятния проблем около магическите кавички. Същността на проблема е в това, че когато конфигурационната директива magic_quotes_gpc е включена, енджина на PHP сам поставя "обезопасителни" наклонени черти преди всички кавички в стойностите на суперглобалните променливи $_GET, $_POST, $_COOKIE, $_SERVER и т.н. Идеята за магическите кавички е възникнала в по-ранните версии на PHP, когато разработчиците на езика са се опасявали, че има твърде много неразумни "разработчици", които никога няма да извикат функцията addslashes() върху някой низ преди да го използват в SQL заявка например. За всички останали разумни хора магическите кавички са просто едно неудобство. Когато те са включени, и някой потребител въведе стойността "It's me" в дадено текстово поле на формуляр, то истинската стойност на променливата, когато тя бъде получена от обработващия PHP скрипт ще бъде "It\'s me". Добре написания PHP код не трябва да разчита на magic_quotes_gpc. Всички разработчици на езика насърчават хората да спрат да използват magic_quotes_gpc. Дори е планувано в PHP6 тази директива да бъде напълно премахната. Как да ги предотвратим? Сега следва да ви покажа няколко начина, чрез които можете да развалите "магията" на магическите кавички. Първи начин: директно от php.ini Ако сървъра е ваш или имате възможност да редактирате php.ini, тогава отворете този файл и просто напишете "Off" срещу директивата magic_quotes_gpc. Втори начин: чрез .htaccess файл Ако хоствате сайта си на споделен сървър, едва ли ще е възможно да редактирате php.ini. Но при повечето хостове е позволено да слагате .htaccess файлове във вашите директории. Напишете следното във файл, наречен ".htaccess": php_flag magic_quotes_gpc "Off" След това качете този файл в директорията, където са вашите PHP скриптове и така те вече няма да бъдат "омагьосвани" от магическите кавички. Трети начин: динамично разваляне на магията по време на изпълнение Сигурно някои от вас си задават въпроса: не може ли това да стане просто с един ред като този: ini_set("magic_quotes_gpc", 0)? Отговорът е НЕ. Ако се разровите в PHP документацията, ще видите, че директивата magic_quotes_gpc е от ниво PHP_INI_PERDIR|PHP_INI_SYSTEM. Това означава, че тя може да се променя по горните два начина, които вече обясних, но не и по време на изпълнение. Причината е в това, че енджина на PHP слага тези наклонени черти още преди изпълнението на скрипта, при регистрирането на суперглобалните променливи. Но както знаете няма невъзможни неща, и аз обичам да казвам, че когато нещо не може да се направи по стандартен начин, винаги е възможно да се заобиколи като се приложи някаква хитрост: <?php if (get_magic_quotes_gpc()) { function traverse (&$arr) { if (!is_array($arr)) return; foreach ($arr as $key => $val) { if (is_array($arr[$key])) { traverse($arr[$key]); } else { $arr[$key] = stripslashes($arr[$key]); } } } $gpc = array(&$_GET, &$_POST, &$_COOKIE); traverse($gpc); } ?> Ако поставите това парче код в началото на вашия скрипт, ще видите, че след него ефекта на магическите кавички ще бъде премахнат. Идеята тук е да се провери дали са включени магическите кавички чрез функцията get_magic_quotes_gpc(), и в случай, че са включени започваме да обхождаме рекурсивно всички елементи на суперглобалните масиви като извикваме за всеки от тях функцията stripslashes(), която премахва наклонените черти. Хубавото на този подход е, че винаги работи, дори когато предните два начина са неприложими. Този начин също е доста подходящ когато искате да пишете преносими PHP скриптове, които не зависят от настройките на конкретната PHP среда, в която вървят. Единствения недостатък тук може би е лекото забавяне на изпълнението на скрипта, но в повечето случаи време от порядъка на 0.005s просто не се усеща. Добра идея е да сложите горния код в отделен файл, например strip_gpc.php. След това в началото на вашите скриптове просто пишете require_once 'strip_gpc.php' и така с един ред премахвате всички главоболия. Да свикнем да пишем код без magic_quotes_gpc След като вече разбрахте как да изключите ефекта на магическите кавички е време да запомните някои важни неща, отнасящи се до сигурността. Най-важното е винаги да използвате addslashes(), там където е необходимо. Пишете SQL заявките така, че да е невъзможно някое по-хитро script kiddie да предизвика грешка в SQL синтаксиса, или по-сериозното - да направи SQL инжекция, което си е доста сериозна заплаха за сигурността. Този кратък пример илюстрира как трябва да се пише PHP код с изключени магически кавички: <?php if (isset($_POST['search_name'])) { // изкарване на стойността на променливата, така както си е въведена от потребителя, // без дразнещите наклонени черти echo "Вие търсите за {$_POST['search_name']}"; ... // при използване в SQL заявки задължително добавяйте наклонени черти, // за да не създавате проблеми на SQL парсера и на себе си :) mysql_query("SELECT * FROM `tbl` WHERE `name`='" . addslashes($_POST['search_name']) . "'"); } ?> След като ви показах всички начини за преборване с досадния проблем наречен "магически кавички", се надявам да съм ви спестил доста нерви и главоболия. Както се казва накрая, happy coding! Автор: Благовест Буюклиев, 17.09.2006

Разглеждащи това в момента 0

  • Няма регистрирани потребители разглеждащи тази страница.

Профил

Навигация

Търсене

Търсене

Конфигуриране на push известия в браузъра

Chrome (Android)
  1. Докоснете иконата на катинар до адресната лента.
  2. Докоснете Разрешения → Известия.
  3. Променете предпочитанията си.
Chrome (Desktop)
  1. Кликнете върху иконата на катинар в адресната лента.
  2. Изберете Настройки на сайта.
  3. Намерете Известия и коригирайте предпочитанията си.