Feedback/optimering av flerfunktionellt php script

Permalänk
Inaktiv

Feedback/optimering av flerfunktionellt php script

Hej!

Jag håller på och skriver en myntdatabas (för folk som samlar på mynt). Jag är ganska ny inom php och tänkte höra om någon här kunde ge lite feedback.

Vad mitt "problem" är att jag skapar POST-data och sedan behandlar det med en ny php fil. Detta har lett min smått avancerade sida att få väldigt många filer.

Jag har prövat att lösa detta med att skapa en hidden input och ange ett värde till 1 och sedan behandlar samma fil som kollar i början om denna är på. Annars skriver den ut en stanard sida.

Är detta en bra lösning eller finns det smartare, bättre lösningar? Blir långa filer om jag skuller implentera detta på hela sidan.

<?php include("include/classes/session.php"); if (!$session->logged_in) {header('Location: main.php');} //Hämta huvud include 'includes/head.php'; ?> <?php $remove = (int)$_POST["remove"]; $removeit = (int)$_POST["removeit"]; $update = (int)$_POST["update"]; if ($removeit == 1){ include 'db_connect.php'; $id = (int)$_GET['id']; if (id == '') {echo "FEL: Inget värde angett"; die();} else { $result = mysql_query("DELETE FROM coin_bases WHERE id='$id'"); } $removeit = 0; echo "Myntet är nu raderat från databasen"; mysql_close(); include 'includes/end.php'; die(); } if ($update = 1) { //MySQL Database Connect include 'db_connect.php'; $id = (int)$_POST["id"]; $A_ID = mysql_real_escape_string($_POST["A_ID"]); $rowd = mysql_real_escape_string($_POST["row"]); $year = mysql_real_escape_string($_POST["year"]); $quality = mysql_real_escape_string($_POST["quality"]); $value = mysql_real_escape_string($_POST["value"]); $type= mysql_real_escape_string($_POST["type"]); $country= mysql_real_escape_string($_POST["country"]); $notes= mysql_real_escape_string($_POST["notes"]); if ($country == '---') { echo "<script type='text/javascript'>alert('FEL: Du måste välja ett land');</script>"; echo "<script language=\"JavaScript\">"; $update = 0; echo "self.location=\"edit.php?id=". $id . "\"; </script>"; die();} $query="UPDATE coin_bases SET A_ID = '$A_ID', row = '$rowd', year = '$year', quality = '$quality', value = '$value', type = '$type', country = '$country', notes = '$notes' WHERE ID='$id'"; mysql_query($query)or die(mysql_error()); mysql_close(); } if ($remove == 1) { include 'db_connect.php'; $id = (int)$_GET['id']; $query = mysql_query("SELECT * FROM coin_bases WHERE id = '$id'") or die(mysql_error()); if(mysql_num_rows($query)>=1){ while($row = mysql_fetch_array($query)) { $A_ID=$row['A_ID']; $rowd=$row['row']; $year=$row['year']; $quality=$row['quality']; $value=$row['value']; $type=$row['type']; $country=$row['country']; $notes=$row['notes']; } ?> <table width="400" border="0" class="CSSTableGenerator1"> <tr> <td> </td> <td> </td> </tr> <tr> <td>*Ark-ID:</td> <td><input name="A_ID" type="text" maxlength="5" value="<?=$A_ID;?>" disabled="disabled" /></td> </tr> <tr> <td>*Rad:</td> <td><input name="row" type="text" maxlength="3" value="<?=$rowd?>" disabled="disabled" /></td> </tr> <tr> <td>*År:</td> <td><input name="year" type="text" maxlength="4" value="<?=$year?>" disabled="disabled" /></td> </tr> <tr> <td>*Kvalité:</td> <td><input name="quality" type="text" maxlength="2" value="<?=$quality?>" disabled="disabled" /></td> </tr> <tr> <td>*Värde:</td> <td><input type="text" name="value" value="<?=$value?>" disabled="disabled" /></td> </tr> <tr> <td>*Valör:</td> <td><input type="text" name="type" value="<?=$type?>" disabled="disabled"/></td> </tr> <tr> <td>*Land:</td> <td><?=$country?></td> </tr> <tr> <td>Notering:</td> <td><input type=" name="notes" value="<?=$notes?>" disabled="disabled" /></td> </tr> <tr> <td> <b>Ändring kan inte ångras.<br />Är du säker?</b> <br /> <form action="edit.php?id=<?=$id?>" method="post"> <input type="hidden" value="1" name ="removeit"> <input type="submit" value="Ja, jag förstår" /></form> <form action="edit.php?id=<?=$id?>" method="post"> <input type="submit" value="Nej, ta mig härifrån" /></form></td> <td> </td> </tr> </table> <?php }else{ echo "Något gick fel"; } } //Om varken update eller remove är markerat else { //MySQL Database Connect include 'db_connect.php'; $id = (int)$_GET['id']; $query = mysql_query("SELECT * FROM coin_bases WHERE id = '$id'") or die(mysql_error()); if(mysql_num_rows($query)>=1){ while($row = mysql_fetch_array($query)) { $A_ID=$row['A_ID']; $rowd=$row['row']; $year=$row['year']; $quality=$row['quality']; $value=$row['value']; $type=$row['type']; $country=$row['country']; $notes=$row['notes']; } ?> <form action="edit.php?id=<?=$id;?>" method="post"> <input type="hidden" name="update" value="1" /> <input type="hidden" name="id" value="<?=$id;?>" /> <table width="400" border="0" class="CSSTableGenerator1"> <tr> <td> </td> <td> </td> </tr> <tr> <td>*Ark-ID:</td> <td><input name="A_ID" type="text" maxlength="5" value="<?=$A_ID;?>" /></td> </tr> <tr> <td>*Rad:</td> <td><input name="row" type="text" maxlength="3" value="<?=$rowd?>" /></td> </tr> <tr> <td>*År:</td> <td><input name="year" type="text" maxlength="4" value="<?=$year?>" /></td> </tr> <tr> <td>*Kvalité:</td> <td><input name="quality" type="text" maxlength="2" value="<?=$quality?>" /></td> </tr> <tr> <td>*Värde:</td> <td><input type="text" name="value" value="<?=$value?>" /></td> </tr> <tr> <td>*Valör:</td> <td><input type="text" name="type" value="<?=$type?>"/></td> </tr> <tr> <td>*Land:</td> <td><?php include 'db_connect.php'; $query="SELECT sa FROM sa ORDER BY sa"; $result = mysql_query($query); echo "<select name=\"country\">"; echo "<option value=\"Sverige\">Sverige</option>\r\n"; echo "<option value=\"---\">---</option>\r\n"; // Lets loop through the result: while($row = mysql_fetch_object($result)) { echo "<option value=\"$row->sa\" "; if ($country == $row->sa){ echo "selected=\"selected\">"; } else {echo ">";} echo "$row->sa</option>\r\n"; } echo "</select>"; ?></td> </tr> <tr> <td>Notering:</td> <td><input type="text" name="notes" value="<?=$notes?>" /></td> </tr> <tr> <td> <input type="submit" value="Genomför ändring"></form>  <form action="edit.php?id=<?=$id?>" method="post"> <input type="hidden" value="1" name="remove" /> <input type="submit" value="Ta bort"></form> </td> <td> </td> </tr> </table> <?php }else{ echo "<script type='text/javascript'>alert('ID existerar inte i databasen');</script>"; echo "<script language=\"JavaScript\"> self.location=\"insert.php\"; </script>"; } mysql_close(); ?> <?php } //Skriv ut slutdesign include 'includes/end.php'; ?>

Permalänk
Medlem

En helt annan sak jag ser direkt som du måste åtgärda är följande:

$id = (int)$_GET['id']; ... $result = mysql_query("DELETE FROM coin_bases WHERE id='$id'");

Detta ger möjlighet till SQL-injection.
Vad händer om någon skriver http://url.till.sida/script.php?id=1';TRUNCATE TABLE? Ja, då skulle ditt PHP-script skriva

$result = mysql_query("DELETE FROM coin_bases WHERE id='1'; TRUNCATE TABLE'");

och all data i din tabell raderas.

Gör istället så här:

$id = mysql_real_escape_string($_GET['id']); ... $result = mysql_query("DELETE FROM coin_bases WHERE id='$id'");

mysql_real_escape_string() förhindrar att någon kan göra så kallade SQL-injections.
Något du alltså alltid ska ange när du skickar POST/GET, inte bara i ovan script.

Lycka till!

Permalänk
Medlem
Skrivet av Zakire:

En helt annan sak jag ser direkt som du måste åtgärda är följande:

$id = (int)$_GET['id']; $result = mysql_query("DELETE FROM coin_bases WHERE id='$id'");

Detta ger möjlighet till SQL-injection.

Nej.

$y = "truncate table"; $x = (int)$y; print $x;

Ger "0".

Sen borde det åtgärdas ändå

Permalänk
Medlem

Om du ändå har olika formulär för funktionerna finns det ingen anledning att lägga in hidden-fält för typen. Ändra i URL:en istället:

<form action="edit.php?id=<?=$id;?>&do=remove" method="post"> ....

Sen så skulle ju jag ha separerat funktionen från gränssnittet, genom att lägga all php-kod i en separat fil. Då kan du på ett överskådligt sätt lägga till mer funktionalitet senare:

include 'db_connect.php'; $action = mysql_real_escape_string($_REQUEST['do']); switch($action){ case "remove": // Kod för att ta bort break; case "update": // Kod för att uppdatera break; } header('Location: /index.php'); exit;

När allt är färdigprocessat skickar du tillbaka användaren till gränssnittet genom en header redirect.

Om du dock har tänkt använda samma formulär så lär du förmodligen ändå ändra vissa saker med javascript, det är då en enkel match att även ändra action på formuläret i samma veva.

Permalänk
Medlem

jag brukar ha en hidden input med "action" sedan en switch $_POST["action"]
case "upload":

function etc etc

break;

Visa signatur

CPU: Ryzen 9 3900x Noctua NH-D14 MOBO: TUF Gaming X570-PLUS GPU: GTX 980 RAM: 32 GB 3200 MHz Chassi: R4 PSU: Corsair AX860 Hörlurar: SteelSeries 840 Mus: Logitech G502 Lightspeed V.v. nämn eller citera mig för att få svar.

Permalänk
Inaktiv

Aha! Smart! Exakt det där med case/break var det jag var ute efter! Mycket lättare att hålla reda på och att lägga till fler funktioner.

Hur är tänket kring mysql_real_escape_string, ska detta användas på allt?

Jättetack för svaren!

Permalänk
Medlem
Skrivet av anon186159:

Aha! Smart! Exakt det där med case/break var det jag var ute efter! Mycket lättare att hålla reda på och att lägga till fler funktioner.

Hur är tänket kring mysql_real_escape_string, ska detta användas på allt?

Jättetack för svaren!

Det ska användas på all data som kan modifieras av användaren/klienten. Hellre för mycket än för litet med andra ord. Observera dock att funktionen kräver en aktiv databasanslutning.

Permalänk
Medlem

Använd t.ex. mysqli eller pdo så slipper du bry dig om mysql_real_escape, det är ramverk som sköter kommunikation åt dig. Smidigare och säkrare, finns jättemånga fler, men dom brukar vara vanliga att börja med.

Annars är det smidigt att escapa alla.
Gör t.ex. en funktion som loopar igenom $_Get och $_post och gör escape på allt innehåll. Så kör du den det första du gör
typ

function Clean(Array $values) { foreach ($values as $key => $value) { $values[$key] = mysql_real_escape_string($value); } return $values; } $_POST = Clean($_POST); $_GET = Clean($_GET);

Sedan finns det lite mer faktorer att ta hänsyn till, och tipset är ändå att gå över till t.ex. mysqli eller pdo (eller ... eller ...) då mysql_connect och mysql_query inte är standard längre. Men det är bra att känna till hur det funkar som grunder. PDO är ganska enkelt att komma igång med och har lätt system att följa.

Visa signatur

"Arguing on internet is like running in the special olympics. Even if you win you're still retarded."

Permalänk
Hedersmedlem

Tar och ger några allmänna gnälliga syntaxsynpunkter, och en del mer allvarliga diton.

Skrivet av anon186159:

<?php include("include/classes/session.php"); if (!$session->logged_in) {header('Location: main.php');}

Likrikta din användning av citationstecken eller apostrofer för strängar. Ibland finns det funktionella skäl för att använda det ena eller det andra, men ovan är det ju samma typ av strängar. Jag föredrar apostrofer, då det blir mindre "skräp" på skärmen att läsa. Dessutom har det en minimal hastighetsvinst då PHP inte behöver parsa strängen för att ersätta variabler, men det är inget egentligt skäl.

Skrivet av anon186159:

//Hämta huvud include 'includes/head.php';

`include` är ett "statement", så det är helt OK att skippa paranteser som här (till och med starkt rekommenderat för att undvika obskyra fällor) — men du bör välja en konvention och hålla dig till den. Tidigare i filen använde du paranteser.

Jag antar att detta är en fil som skriver ut din "HTML-start", så att säga — låt den vänta till efter du har gjort alla databasanrop och annan hantering! Skriv ut all HTML i en sektion i filen i stället för att blanda hipp som happ. Se senare mer utförliga resonemang om detta.

Skrivet av anon186159:

Det är onödigt att stänga och därefter direkt öppna taggen igen. Återigen så kostar det egentligen ingenting extra i "prestanda", så det är inte skälet, men det är något som leder till väldigt många problem för nybörjare av typen Cannot modify header information - headers already sent. Dessutom är det fler tecken till ingen nytta, vilket ofta är en bra indikator på att det kan skippas.

Skrivet av anon186159:

$removeit = (int)$_POST["removeit"]; if ($removeit == 1){

Enklare är att använda `if (isset($_POST['removeit'])) {` — jag antar att du inte har fler flaggor än "på" eller "av" ändå.

Skrivet av anon186159:

$id = (int)$_GET['id']; if (id == '') {echo "FEL: Inget värde angett"; die();}

Här ligger du farligt till för att gå på en nit gällande PHPs dynamiska typning. Den tomma strängen evaluerar booleanskt till "falskt", vilket motsvaras av `0`. Om någon anger `id` till att vara `0` så kommer ditt test ge `true` och anslutningen dö:

$ php -r '$id = 0; if ($id == "") echo "Sant!";' Sant!

Ett problem är att typkonverteringen kastar strängar till `0`, så du kan just nu inte särskilja på värdet 0 och felaktiga värden. Du skulle kunna testa med `is_numeric` innan typkastningen och konvertera flyttal till motsvarande `int`; alternativt kan du skriva en egen "motsvarar denna sträng ett heltal?"-funktion, vilket saknas i standardbiblioteket (`is_int()` gör inte detta) men går att göra på någon rad. Du kan också kontrollera specialfallet när `id` är `0` innan du gör typkastningen.

Skrivet av anon186159:

$result = mysql_query("DELETE FROM coin_bases WHERE id='$id'");

Som redan nämnts så har du mycket att vinna på att gå över till PDO eller `mysqli`. Dels är det mer framtidssäkert, men framför allt så är det säkrare. Mycket av de indatakontroller du gör sköts automatiskt av de nya gränssnitten, och det blir betydligt mycket svårare att råka göra fel (till och med omöjligt i många vanliga fall). Mindre att tänka på, bara fördelar (utöver att man får lära sig något nytt då, men det är ju egentligen också en fördel!).

Skrivet av anon186159:

$removeit = 0;

Du använder inte variablen `$removeit` igen i skriptet, så det är onödigt att "nolla" den. Se också tidigare anmärkning om att det snarare bara bör vara en "är den satt eller inte?"- än en "har den värde 1 eller 0"-variabel.

Skrivet av anon186159:

echo "Myntet är nu raderat från databasen"; mysql_close(); include 'includes/end.php'; die();

Detta kodblock är på fel indenteringsnivå. "Herregud vad gnälligt!" — ja, men det påvisar också att du inte använder en bra editor, skulle jag säga. Indentering är ej heller värdelöst: hela anledning till indenteringen är ju för att man snabbt ska kunna se vad koden gör, och att kunna läsa koden är enormt viktigt för felsökning och annat. Kod läses mer än den skrivs, så det som förenklar läsandet är väl spenderad tid.

Skrivet av anon186159:

if ($update = 1) {

Klassiskt och ofta allvarligt logikfel: du ska ha `==` (eller egentligen hellre `===` för att kontrollera typ och inte bara implicit booleanskt värde, eller här än hellre `isset()` som nämndes tidigare) och definitivt inte `=` här. Nu frågar du PHP: "kan du sätta variabeln `$update` till `1`?", och om PHP lyckas med denna rätt enkla uppgift så går vi in i `if`-blocket, vilket alltså alltid kommer hända (om inte strömmen går).

Skrivet av anon186159:

//MySQL Database Connect include 'db_connect.php'; $id = (int)$_POST["id"];

Nu blandar vi indentering igen, och går dessutom över till fyra mellanslag i stället för tab. Inga problem i funktion, men det är lite slarvigt. Att visa hänsyn till detaljer är något som genomsyrar programmering, så det är värt att vara konsekvent i allt (tills man aktivt väljer att frångå en konvention av någon anledning, vilket kan hända).

Skrivet av anon186159:

if ($country == '---') { echo "<script type='text/javascript'>alert('FEL: Du måste välja ett land');</script>";

Detta är snarare en kontroll som du bör göra innan användaren har skickat iväg formuläret. Tanken med skript som körs på klientsidan (så som Javascript) i kontrast med serverbaserade språk (så som PHP) är att klienten själv kan lösa sådana problem innan servern behöver börja bry sig. Det sparar tid för alla. Du behöver ändå ha kontroller på serversidan, för det är lätt för en medvetet elak klient att kringgå Javascriptkontroller, och alla klienter har det inte aktiverat (faktiskt), men att dynamiskt generera Javascript när man redan tagit rundan till servern är onödigt. Det ska dessutom mycket till för att en `alert()`-ruta ska vara ett trevligt presentationsalternativ, men det är en implementationsdetalj.

Skrivet av anon186159:

echo "<script language=\"JavaScript\">"; $update = 0; echo "self.location=\"edit.php?id=". $id . "\"; </script>"; die();}

Du har `header()`-funktionen i PHP för att omdirigera klienten: använd den. Att skriva ut Javascript på detta sättet är väldigt bakvänt, och en väldigt dålig vana.

Det är sedan många anmärkningar som upprepas i kodstyckena som följer.

———

Ett annat problem är att du upprepar stora delar av koden, och det är blir svårt att följa kodgången så som det är skrivet. I praktiken så skriver du ju ut egentligen samma formulär, med den lilla skillnaden att du sätter `disabled` om data redan är skickat. Enklare vore kanske att skriva ut `disabled` (`disabled="disabled"` behövs inte i "modern" HTML — se avslutande anmärkning i detta inlägg) ifall flaggan är satt. Det gör att du får hälften så mycket kod att hålla reda på, och om du ändrar något på ett ställe så ändras det även på ett annat.

Ett sätt att minimera koddubblering är att skriva funktioner som gör repetitiva saker på en centraliserad plats. Exakt vilka funktioner som passar beror på fall-till-fall-bedömningar.

En riktlinje vad gäller att använda PHP på ett överskådligt sätt i mindre hemapplikationer är att all egentlig logik ska ligga i sidans huvud, eller än hellre i externa filer (till sin spets kan man säga att en kodfil antingen bara ska definiera funktioner (och/eller konstanter) eller inte alls). Första gången du snuddar vid att skriva ut HTML-kod så ska alla databasfrågor vara färdigförberedda, alla datastrukturer populerade, alla variabler satta, alla funktioner definierade, etc., och det enda som kvarstår är att använda PHP som en ren "templating engine", med enkla loopar, villkorssatser och variabelutskrifter inblandat i HTML-koden. Detta är något bör vara ditt rättesnöre i att omorganisera ditt skript: se till att isolera databasbehandlingen med inskickade formulärvärde i ett eget initialt stycke, och låt presentationen på samma sätt ligga koncentrerad i slutet av dokumentet. Börjar det bli alltför mycket logik i huvudet av en viss fil, så dela upp den i funktioner i filer som du inkluderar. En sådan organisering, där man särskiljer logik från presentation, är troligen det nyttigast tipset för någon som är ny med PHP att ta till sig, för det underlättar enormt.

Tänk också på att allt som skrivs ut i presentationsdelen av HTML-segmentet från generella strängar ska masseras med `htmlspecialchars()`. Allt som ska skrivas ut till användaren ska behandlas på ett säkert sätt, på samma sätt som allt som ska in till en databas ska behandlas speciellt. En bra tumregel är att man måste kunna motivera varför man inte använder en liknande funktion på alla strängar man skriver ut. Är svaret "äsch, orkar inte skriva htmlspecialchars()" så är det ett dåligt svar . Är detta ett stort problem så kan man definiera exempelvis `function h(str) {htmlspecialchars(str);}` i sitt standardbibliotek så slipper man skriva så mycket framöver.

Att vara konsekvent med sin struktur, och inte blanda presentationen med logiken, är något som gör det mycket enklare att utvidga sina skript i framtiden, utan att man sitter med ett härke som man drar sig för att ens röra, och som gör konstiga saker när man ändrar minsta lilla. Det syns ganska tydligt att den kod du visar har växt "organiskt" allt eftersom du lärt dig mer, utan att ha genomgått de större omorganiseringar som ibland kan vara nödvändiga längs vägen.

Skrivet av anon186159:

<input type="hidden" value="1" name="remove" /> <input type="submit" value="Ta bort">

Du blandar mellan att använda självstängande taggar och att inte göra det. Återigen: försök vara konsekvent. Självstängning behövs ej heller i HTML-dokument. Du visar inte din dokumentbörjan, så jag vet inte vilken DOCTYPE du anger för dokumentet (ifall det är det idag lite arkaiska XHTML så kan det kräva självstängande taggar), men i vilket fall så ska det inte behöva blandas.

———

Tillägg:

Skrivet av anon186159:

$value = mysql_real_escape_string($_POST["value"]); $type= mysql_real_escape_string($_POST["type"]); […] $A_ID=$row['A_ID'];

Här har du blandat tre konventioner för vitutrymme runt tilldelningstecknet: " = ", "= " och "=". Använd en (med fördel den första).

Du blandar även konventioner för variabelnamn och vektorindex, där `A_ID` skrivs med versaler och underscore ordavskiljare, vilket inte används i övrigt.

Skrivet av anon186159:

echo "<script language=\"JavaScript\">"; $update = 0; echo "self.location=\"edit.php?id=". $id . "\"; </script>"; die();}

Inuti citationstecken behöver du inte lämna strängen för att skriva variabler, vilket är en av poängerna med dessa. `$update` behöver du inte "nolla". Ovanstående skrivs enklare som endera av:

echo "<script language=\"javascript\">self.location=\"edit.php?id=$id\";</script>"; echo '<script language="javascript">self.location="edit.php?id=' . $id . '";</script>';

eller så kan du helt lämna PHP-omgivningen när du ska skriva ut längre HTML-stycken enligt:

?> <script language="javascript">self.location="edit.php?id=<?=$id?>";</script> <?php

så slipper du bry dig så mycket om escaperegeler. Detta brukar vara mest läsbart.

Skrivet av anon186159:

<table width="400" border="0" class="CSSTableGenerator1"> <tr> <td> </td> <td> </td> </tr>

Varför börja med en tom rad? Vill du ha avstånd så använd CSS-regler.

Skrivet av anon186159:

<td>*År:</td>

Om du anger rätt teckenkodning i ditt HTML-dokument så kan du åtminstone slippa att behöva escapea våra vanliga svenska tecken i utskrifter. "År:" är lättare att läsa än "År:". "&", "<" och ">" behöver fortfarande skrivas som entiteter, och i URL-strängar och HTML-attribut så behöver man vara mer noggrann (men URL-strängar låter man PHP:s inbyggda funktioner rendera, som löser detta transparent), men i övrigt så löser teckenkodningn UTF-8 en mängd av de problem som internationalisering medför. Se Using character escapes in markup and CSS [W3C] om mer info önskas.

Skrivet av anon186159:

<td><input name="quality" type="text" maxlength="2" value="<?=$quality?>" disabled="disabled" /></td> <td><input type="text" name="value" value="<?=$value?>" disabled="disabled" /></td>

Här blandas ordningen på attributen `type` och `name`. Inget problem tolkningsmässigt, men återigen så ser du lättare problem i koden om du är konsekvent med sådant.

Skrivet av anon186159:

echo "<select name=\"country\">"; echo "<option value=\"Sverige\">Sverige</option>\r\n"; echo "<option value=\"---\">---</option>\r\n";

Ska du skriva stycken med HTML-kod så är det enklare att avsluta PHP-omgivningen och därefter starta den igen:

?> <select name="country"> <option value="Sverige">Sverige</option> <option value="---">---</option> <?php

Detta sätt använder du även på flera andra ställen i koden.

Skrivet av anon186159:

<input type="submit" value="Genomför ändring"></form> 

Det där avslutande hårda mellanslaget känns rätt främmande: inget större problem i sig, men det går in i hela bilden av att koden är lite "slarvigt" skriven. Jag antar att den till viss del skrivits i en WYSIWYG-editor för att sedan bli berikad med PHP. WYSIWYG ger ofta onödig kod vilket gör det svårare att ha kontroll över vad som faktiskt händer.

Som sades i början: många petigheter, men din frågeställning kom just av att du kände att din började bli svår att underhålla och utöka. Alla dessa detaljer är saker som bidrar till detta. Även om man i "inspirationens hetta" kan hålla koll på vad alla olika delar i en kodfil gör, och hålla tungan rätt i mun gällande avancerade nästade villkorssatser, så skjuter man sig själv i foten gällande nästa gång man behöver titta på koden ifall man inte lagt extra ansträngningar på att koda tydligt.

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Permalänk
Medlem
Skrivet av orig_rejser:

Använd t.ex. mysqli eller pdo så slipper du bry dig om mysql_real_escape, det är ramverk som sköter kommunikation åt dig. Smidigare och säkrare, finns jättemånga fler, men dom brukar vara vanliga att börja med.

Annars är det smidigt att escapa alla.
Gör t.ex. en funktion som loopar igenom $_Get och $_post och gör escape på allt innehåll. Så kör du den det första du gör
typ

function Clean(Array $values) { foreach ($values as $key => $value) { $values[$key] = mysql_real_escape_string($value); } return $values; } $_POST = Clean($_POST); $_GET = Clean($_GET);

Sedan finns det lite mer faktorer att ta hänsyn till, och tipset är ändå att gå över till t.ex. mysqli eller pdo (eller ... eller ...) då mysql_connect och mysql_query inte är standard längre. Men det är bra att känna till hur det funkar som grunder. PDO är ganska enkelt att komma igång med och har lätt system att följa.

Nja. MySQLi är en förbättrad version av MySQL, men skyddar dig inte mot skadlig indata. Dock så ska man istället använda funktionen mysqli_real_escape_string(). PDO/prepared statements däremot fungerar så som du säger.

Permalänk
Hedersmedlem
Skrivet av Full Strike:

Nja. MySQLi är en förbättrad version av MySQL, men skyddar dig inte mot skadlig indata. Dock så ska man istället använda funktionen mysqli_real_escape_string(). PDO/prepared statements däremot fungerar så som du säger.

`mysqli` stöder också prepared statements till fullo, så den erbjuder samma funktionalitet som PDO. `mysqli` tillåter även direkta queries, men det gör PDO också, så de är rätt ekvivalenta i detta hänseende.

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Permalänk
Medlem
Skrivet av phz:

`mysqli` stöder också prepared statements till fullo, så den erbjuder samma funktionalitet som PDO. `mysqli` tillåter även direkta queries, men det gör PDO också, så de är rätt ekvivalenta i detta hänseende.

Ja, var kanske lite otydlig. Min poäng var att man inte ska utgå från att man är skyddad bara för att man använder MySQLi, för det krävs prepared statements.

Permalänk
Inaktiv

Ojsan. Här kom det riktigt bra med feedback! Har försökt att ta till mig så mycket som möjligt från det ni har skrivit. Däremot så är det så mycket kod och jag vinner inget på att gå över till mysqli etc. att jag skippat det men tills nästa projekt ska jag definitivt uppgradera mig en level till!

Jag har helt enkelt nu börjat med att radikalt skriva om hela koden. Har börjat med startsidan, vilket är insert.php (man lägger ett mynt för ett ark eller en rulle).

head.php Huvud för template (mest bara för att visa logiken i övrigt)
config.php
base_functions.php Har gjort funktioner för att få bort så mycket onödigt repeterande som möjligt
process_insert.php Här processar vi insert.php. Nu blir allt SÅ mycket enklare att lägga till mer funktioner och följa min egen kod
insert.php Var skriven i grunden som edit.php (det jag postade först). Och har som sagt försökt att plocka ur så mycket php kod jag har kunnat.

Kör XHTML 1.0 Transitional (om jag ska vara helt ärlig så har jag noll koll på vad man ska välja. Detta var default från Dreamweaver.) Bör jag välja någon annan? I övrigt så valideras min kod till Valid hos W3C Validator.

Och på tal om Dreamweaver. Finns det något bättre PHP programmeringsprogram? Med tanke på att det antyddes att det var något knas med min WYSIWYG (och jag använder faktiskt inte WYSIWYG, så Dreamweaver är kanske överflödigt). Förslag tas gärna emot.

Angående åäö så växte koden fram dynamiskt och precis i början var jag tvungen att hårdkoda dessa. Men efter jag lade till en ordentlig design så var det ju inte längre något problem. Ser dock ingen anledning till att ändra om alla åäö.

PHP klagar på undefined variable. Dessa är till för min check till min head.php för att slippa ropa in javascript i onödan. Är detta något jag måste bry mig om? Dock så tar det ju alltid emot att få upp felmeddelanden/varningar.

//-------------DECLARE-VARIABLES--------- //Declare numberformat $numberformat = ''; //Declare tinymce $tinymce = ''; //Declare tabs $tabs = '';

Lägger jag till detta i config.php så försvinner felmeddelandet. Däremot så slutar min kod att fungera korrekt.

Sedan undrar jag hur man avgör när man ska använda == eller ===

Alltså ett riktigt tack för att ni verkligen har lagt ner er för att hjälpa mig att bli en bättre kodare!

En bild på hur det ser ut: http://postimg.org/image/xqwjbmhvp/full/

Permalänk
Medlem
Skrivet av anon186159:

Kör XHTML 1.0 Transitional (om jag ska vara helt ärlig så har jag noll koll på vad man ska välja. Detta var default från Dreamweaver.) Bör jag välja någon annan? I övrigt så valideras min kod till Valid hos W3C Validator.

Här skulle jag ha valt HTML5, dock vet jag inte om det är rätt val att gå men i och med att det är tänkt att bli den nya standarden så har jag valt att fortsätta med det.
Dock fungerar XHTML i princip lika bra.

Skrivet av anon186159:

Och på tal om Dreamweaver. Finns det något bättre PHP programmeringsprogram? Med tanke på att det antyddes att det var något knas med min WYSIWYG (och jag använder faktiskt inte WYSIWYG, så Dreamweaver är kanske överflödigt). Förslag tas gärna emot.

Dreamviewer är faktiskt WYSIWYG om man är inne i Design-läget, är man däremot inne i Kod-läget så är det som en vanlig editor.
Jag själv har testat några olika, t.ex:
Notepad++
PhpDesigner
Sublime Text

Dessa 3 är väl dom jag anser är rätt trevliga, detta är dock en smaksak och vad man har för krav från din editor.
I nuläget använder jag Sublime Text.

Skrivet av anon186159:

PHP klagar på undefined variable. Dessa är till för min check till min head.php för att slippa ropa in javascript i onödan. Är detta något jag måste bry mig om? Dock så tar det ju alltid emot att få upp felmeddelanden/varningar.

//-------------DECLARE-VARIABLES--------- //Declare numberformat $numberformat = ''; //Declare tinymce $tinymce = ''; //Declare tabs $tabs = '';

Lägger jag till detta i config.php så försvinner felmeddelandet. Däremot så slutar min kod att fungera korrekt.

Varför du får felmeddelanden/varningar är för att du försöker skriva ut något som inte är tilldelat, dessa variabler har alltså inte blivit deklarerade innan du använder dom första gången.
Tilldela variablerna något värde INNAN du ska använda dom så slipper du problemet, vet inte exakt hur det ser ut nu då jag inte kollat på all kod ifall det finns där.

Skrivet av anon186159:

Sedan undrar jag hur man avgör när man ska använda == eller ===

Förklarar detta väldigt kort.
== Kollar så att något är lika med medans
=== Kollar så att det är lika med men ÄVEN av samma datatyp.

T.ex

$test = 5 == 5; // Returnerar resultatet 1 då det är true $test = 5 === '5'; // Fungerar inte lika bra, kommer bli ett tomt resultat (false)

Permalänk
Hedersmedlem

Notis: nästlade [QUOTE]- och [PHP]-taggar bygger ordentligt på höjden i forumet, så det blir snabbt väldigt mycket att scrolla när man delar upp det som jag gör… Men det får ni stå ut med!
Tillägg: om ni läser detta i SweClockers 6.0 så kanske ovanstående inte gäller…

Skrivet av anon186159:

Däremot så är det så mycket kod och jag vinner inget på att gå över till mysqli etc. att jag skippat det men tills nästa projekt ska jag definitivt uppgradera mig en level till!

Du vinner i prestanda (vilket troligen är helt försumbart, och inte ett argument här) och i säkerhet. Det är inte bara godhjärtade numismatiker som kommer använda din sida, utan även automatiserade skript från datorer världen över som konstant söker efter sårbarheter att utnyttja. Man får alltid väga in hotbild, men tja. Det är inte bortkastad tid att göra saker "rätt" vad gäller just databaskommunikation, vilket är det absolut vanligaste säkerhetsproblemet i PHP-kod världen över, skulle jag tro.

Ska du ändå radikalt skriva om koden så är det ett bra tillfälle. De ändringar som krävs är oftast bara att man lägger till rader och "låser" variabler till databassvar; i praktiken ger det överskådligare kod i slutändan. Det är troligen en av de saker som kommer ge mest tandagnisslan innan du får den "korrekt", men när väl polletten trillat ner så är det enkelt framöver.

Genomgång av filerna:

head.php

Skrivet av intervet:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

XHTML Transitional är lite daterat (XHTML var det "nya heta" runt år 2000). Det fungerar givetvis, men man har mycket att vinna i förenkling om man går över till HTML5, som är explicit designat för att vara bakåtkompatibelt till Hedenhöstiden. Om du tar bort en massa tecken och skriver ovanstående som:

<!DOCTYPE html> <html> <head> <meta charset="utf-8">

så har du helt plötsligt ett fullkomligt giltigt HTML5-dokument. Mindre kod, mer läsbart → bättre! Notera att vi inte behöver självstängande taggar (hela konceptet med självstängande taggar är egentligen inte ens applicerbart i "vanlig" HTML jämfört med XHTML), och att vi kunde använda en enklare syntax för att ange teckenkodning. Det finns liknande syntaxförenklingar på andra håll, men HTML5 är som sagt också bakåtkompatibelt. Det finns alltså saker att vinna på att uppdatera resterande kod, men egentligen inget att förlora på att behålla saker som de är, utan ändringarna kan ske mjukt efterhand.

Skrivet av intervet:

<link rel="SHORTCUT ICON" href="http://blablabla.se/coin/favicon.ico"/>

`rel="shortcut icon"` är en antik kvarleva som bara finns med av bakåtkompatibilitetsskäl: skriv i stället bara `rel="icon"`, som gör samma sak. Och om du ändrar till HTML5 så behöver du inte den avslutande slashen, men det kommer gälla överallt nedan, så det upprepar jag inte igen.

Skrivet av intervet:

<link href="default.css" rel="stylesheet" type="text/css" media="all" />

I HTML5 så skriver man ekvivalent:

<link rel="stylesheet" href="default.css">

`media="all"` är defaultvärdet i HTML5 (tidigare var default `media="screen"`, men i praktiken tolkade alla läsare det på samma sätt som `media="all"` ändå…).

I HTML5 så noterade man också att alla stylesheets de facto är `type="text/css"`, så det behövs inte längre. Detsamma gäller `type="text/javascript"` i `<script>`-taggar.

Skrivet av intervet:

<!--[if IE 6]><link href="default_ie6.css" rel="stylesheet" type="text/css" /><![endif]-->

Behöver vi stödja IE6 längre? Stora aktörer som Google slutade med detta redan för fyra år sedan. Tid som läggs på att explivit stödja IE6 vore nog bättre lagd på andra saker.

Skrivet av intervet:

echo " <script type=\"text/javascript\" src=\"development-bundle/jquery-1.10.2.js\"></script> <script type=\"text/javascript\" src=\"js/tab.js\"></script>";}

För att undvika att behöva escapea citationstecken och annat så är det enklare att hoppa ur PHP-läget helt som visades tidigare (och som du gör på vissa ställen). Alternativt (men sämre, då en editor vanligen inte automatiskt kan tolka detta som HTML) kan man använda så kallad heredoc syntax för att skriva längre avsnitt av strängar; men just för HTML-kod är det nog enklast att gå ur PHP-läge.

Notera också det jag skrev om HTML5 ovan: `type="text/javascript"` behövs inte där.

Skrivet av intervet:

<h1><img src="images/logo.png" alt="coin" />Coin<span>Base</span></h1>

Ge `height` och `width` också: då kan en browser allokera rätt dimensioner direkt när koden läses, utan att behöva flytta på element igen när bilden laddats.

include.php

Skrivet av intervet:

$DBUSER = "root";

Bättre att ha en dedikerad användare med begränsade rättigheter; din myntdatabasanvändare behöver ju exempelvis inte kunna skapa nya användare och tabeller, eller ta bort hela databasen. En del i säkerhetsmodellen är att användare ska ha definierade roller efter behov.

Skrivet av intervet:

//FORCE SSL //1 for on. 0 for off $FORCE_SSL = "0";

Använd `true` och `false` i stället. Det säger mycket mer naturligt vad som menas. Detta gäller på fler ställen i koden där du använder liknande "flaggor".

Skrivet av intervet:

if ($FORCE_SSL == 1) {

`if` är egentligen bara intresserat av `true` eller `false`. Konstruktionen med `($FORCE_SSL == 1)` använder en inbyggd operator som jämför två variabler, och returnerar just `true` om de är lika, och `false` om de inte är det. Eftersom `1` implicit är `true` i PHP och `0` är `false` så kan det enklare skrivas:

if ($FORCE_SSL) {

Än enklare att följa blir det ju om man redan från börjat definierat `$FORCE_SSL = true;`, vilket ändå är vad man menar. `true` och `false` är inbyggda nyckelord i PHP.

Skrivet av intervet:

if ($FORCE_SSL) { if($_SERVER["HTTPS"] != "on") { header("Location: https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]); exit(); } }

Indenteringen rasar lite här, och konventionen för `if` ändras. Stycket borde snarare vara:

if ($FORCE_SSL) { if ($_SERVER["HTTPS"] != "on") { header("Location: https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]); exit(); } }

för att vara konsekvent, eller än enklare:

if ($FORCE_SSL && $_SERVER["HTTPS"] != "on") { header("Location: https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]); exit(); }

Notera också att det med "indentering" inte menas att man ska sitta och trycka på mellanslagstangenten 12 gånger varje gång man byter rad: en bra editor löser detta åt dig.

Gällande kontrollen i sig så säger manualen bara att `$_SERVER['HTTPS']` är "non-empty" om man kallat via HTTPS, så testet borde kanske snarare vara `if (empty($_SERVER['HTTPS']))` och inte strängjämförelse (notera dock att PHP via ISAPI på IIS (vilket sedan PHP 5.3.0 inte längre är supportat) av någon !"#¤% anledning returnerar "off" om det inte är satt).

För minnes skull kan man notera att det finns en liten fälla i att bygga egna kompletta URL:er som du gör om man exempelvis har servern på en icke-standard port för protokollet (se det för närvarande näst högst rankade, men mer korrekta, svaret från Timo Huovinen på Get the full URL in PHP [SO]), men i ditt fall fungerar det utan problem, så länge HTTPS-servern körs på port 443. Nämner det främst för att det kan ge oväntade resultat på utvecklingsservrar där man kanske använder icke-standardportar.

base_functions.php

Skrivet av intervet:

function getCountries() { include ('db_connect.php'); $query="SELECT sa FROM sa ORDER BY sa"; $result = mysql_query($query); // Lets loop through the result: while($row = mysql_fetch_object($result)) { echo "<option value=\"$row->sa\">$row->sa</option>"; } }

Indenteringen har försvunnit lite igen. `$query`-tilldelningen saknar mellanslag runt `=`. Du kan också kolla upp funktionen `include_once()`, och kanske ännu mer skillnaden mellan `include` och `require`. Här (och i resten av databasfunktionerna) skulle troligen `include_once` eller möjligen `require_once` passa bäst.

Skrivet av intervet:

function getAIDplusone() { include ('db_connect.php'); $rowSQL = mysql_query("SELECT MAX(A_ID) AS max FROM coin_bases"); $row = mysql_fetch_array( $rowSQL ); $largestNumber = $row['max']; echo $largestNumber+1; mysql_close(); }

Som ovan. Argumentet till `mysql_fetch_array()` bryter konventionen då det är omgivet av mellanslag, så bort med dem. Vissa rader avslutas med tabbtecken, vilket återigen inte är något problem i funktionalitetssynpunkt, men om man delar kod med andra så är detta inte så poppis, då det är lite slarvigt.

Dessutom: vad gör funktionen? Den returnerar nästa "lediga" ID i din databas — men din databas bör sköta tilldelningen av ID själv med hjälp av `auto_increment`! Du ska inte behöva bry dig om detta, så denna funktion borde inte behövas. Det är något som kan behövas tänkas om i databasdesignen här; kanske behövs ett inkrementellt ID för databasens skull, samt ett ID för "verkliga livets" skull, beroende på hur saker används.

För namngivning av funktioner finns två vanliga standarder: antingen `function_names_with_underscores` i gemena tecken, eller `functionNamesInCamelCase`. Vilken som är vanligast beror på språk och ofta preferens. I PHP är det senare vanligare. Det är fördelaktigt att välja en av dessa konventioner. Det finns liknande konventioner för variabelnamn, konstanter, etc., så enbart genom att se hur namnet är skrivet så kan hjärnan koppla till vad det är för objekt, vilket gör koden snabbare att förstå.

Snarare än att ha ett `echo`-uttryck i funktionen, så vore det mer naturligt med att du returnerar ett värde med `return` och skriver ut det med `echo` där det behövs, dvs att du i filen senare kallar `echo getAIDplusone();` (vilket också gör att du kan använda snabbkonstruktionen `<?=getAIDplusone()?>`). Annars borde funktionen snarare heta `echoAIDplusone()`, men det är en onaturlig konstruktion här.

Skrivet av intervet:

function getAIDplusoneroll()

Som ovan. Att döma av funktionen så funderar jag på om du har en tabell för både "mynt" och "rolls", där ID-fältet inte är unikt i tabellen, utan bara per typ..? I så fall bör du splitta dessa typer till två tabeller, eller låta ID-fältet vara unikt för båda (dvs om du har ett mynt med `id=5` så kan du inte ha en "roll" med `id=5`).

Databaser använder dessa unika ID:n för att kunna indexera en databas och snabbt och effektivt hitta rader, så de ska vara unika.

Skrivet av intervet:

?>

I "rena funktionsfiler" i PHP, dvs filer utan egen output, så rekommenderas det faktiskt att skippa den avslutande taggen. PHP-tolken avslutar ändå detta själv när filen tar slut, och att avsluta manuellt kan ge upphov till problem; se manualen och Why would one omit the close tag? [SO].

process_insert.php

Skrivet av intervet:

$action = mysql_real_escape_string($_REQUEST['do']); switch($action){ case "add": //Check for requiered values

Ja, `switch` passar väl in här. Det blir nog en tydlig förbättring vad gäller att kunna hålla koden ren. Konventionen ger att det borde vara ett mellanslag innan `{`, och det borde vara fyra mellanslags indentering, inte tre, för `case`. På nästa rad blandas mellanslag och tabbar för indentering, vilket aldrig ska göras. (((Stavning: "required"))).

Skrivet av intervet:

//Check for requiered values if ($A_ID == '' || $row == '' || $year == '' || $quality == '' || $value == '' || $type == '' || $country == '---') {

Här är det återigen problemet med PHP:s lösa typning och vad som är "falskt". Vill du jämföra mot den tomma strängen så ska du använda `===`: här jämför du implicerade booleanska värden, så strängen 0 är faktiskt "lika med" den tomma strängen här, vilket inte är riktigt vad du vill. Du skulle med fördel kunna använda `empty()` som nämndes innan.

Skrivet av intervet:

header('Location: /insert.php?do=success');

En vanlig "konvention" är att man lägger till `exit()` efter `header()`. Det finns en viss säkerhetsaspekt i detta då inga knasigheter (företrädelsevis programmerarmisstag) ska kunna få skriptet att fortsätta efter denna punkt. "Hängslen och livrem". Du använder detta på vissa andra ställen (exempelvis i slutet av just denna fil), så i konsekvensens namn skulle det nog även vara på dessa ställen, så nära anropen som möjligt.

insert.php

Skrivet av intervet:

<ul class="tabs"> <li><a href="#tab1">Lägg till ett ark</a></li> <li><a href="#tab2">Lägg till en rulle</a></li> </ul> <div id="tab1">

Ville bara flika in att indenteringen är lite bananas här :-).

Skrivet av intervet:

<form action="function/process_insert.php?do=add" method="post">

I stället för att blanda in en query-sträng i `action`-URL:en så är det nog tydligare enklare att lägga ett `hidden` fält i formuläret. Det finns faktiskt en "regel" gällande när man ska använda `POST`- eller `GET`-metoder i HTTP-specifikation: `POST` används om aktionen har sidoeffekter (exempelvis att lägga till/modifiera/radera saker i en databas), annars används `GET` (exempelvis för att kalla på en viss undersida, etc.). `GET` är alltså något som är vettigt att en användare ska kunna vilja lägga i sina bokmärken, men inte `POST`. I längre ordalag: HTTP 1.1 [W3C].

Skrivet av intervet:

<td><input name="A_ID" type="text" maxlength="5" /></td>

Om du går över till HTML5 så bör du också kolla upp vad attributet `required` kan göra för dina användare; kort sagt, så om det läggs till så kommer användarens webbläsare tydligt och direkt säga till användaren om något fält som är nödvändigt att fylla i, och inte skicka iväg formuläret förrän detta är fixat. Då slipper server behandla en förfrågan som ändå bara refuseras, och det blir en bättre upplevelse för användaren.

Skrivet av intervet:

<input name="is_roll" type="hidden" value="1" />

Du måste inte sätta `value="1"`, då du ju egentligen bara är intresserad av om variabeln överhuvudtaget är satt eller inte. Om du skippar `value` och kontrollerar `isset($_POST['is_roll'])` så får du samma effekt. Notera att om `value` saknas så har variabeln inget värde, men den är likväl satt. Skillnaden däremellan är bra att ha koll på, så att man även ser skillnaden mellan `isset()` och `empty()` fullt ut.

Skrivet av intervet:

<?php getCountries();?>

Jag skulle snarare döpt funktionen till `printCountryOptions()` eller något, om den nu faktiskt skriver ut ("print") saker och inte bara hämtar ("get") saker. Att kunna se direkt på funktionens namn vad man kan förvänta sig hända är också bra ur läsbarhetssynpunkt.

Skrivet av anon186159:

insert.php Var skriven i grunden som edit.php (det jag postade först). Och har som sagt försökt att plocka ur så mycket php kod jag har kunnat.

Det ser betydligt enklare ut att följa nu jämfört med innan, så jag skulle säga att det redan har gett resultat.

Skrivet av anon186159:

Kör XHTML 1.0 Transitional (om jag ska vara helt ärlig så har jag noll koll på vad man ska välja. Detta var default från Dreamweaver.) Bör jag välja någon annan? I övrigt så valideras min kod till Valid hos W3C Validator.

HTML5, dvs att egentligen inte ge någon specifik dialekt alls i sin doctype, är framtidssäkert, och enklare, rent ut sagt.

(XHTML Transitional var egentligen en rätt märklig standard, då den bara var tänkt att vara en övergång, men det är en annan diskussion.)

Skrivet av anon186159:

Och på tal om Dreamweaver. Finns det något bättre PHP programmeringsprogram? Med tanke på att det antyddes att det var något knas med min WYSIWYG (och jag använder faktiskt inte WYSIWYG, så Dreamweaver är kanske överflödigt). Förslag tas gärna emot.

Någon vass texteditor tycker jag är trevligt, och mer lär inte behövas för projekt i denna skala. Notepad++ är vanligt på Windows. Jag använder Vim.

Skrivet av anon186159:

Angående åäö så växte koden fram dynamiskt och precis i början var jag tvungen att hårdkoda dessa. Men efter jag lade till en ordentlig design så var det ju inte längre något problem. Ser dock ingen anledning till att ändra om alla åäö.

Nej, det är inga problem att ha kvar entities, utöver att det gör koden lite svårare att läsa. Med en "vass texteditor" som jag nämnde ovan så är det en snabb operation att ändra alla dessa en gång för alla med "sök och ersätt"-funktioner, men det är ingen prioritet :-) .

Skrivet av anon186159:

PHP klagar på undefined variable. Dessa är till för min check till min head.php för att slippa ropa in javascript i onödan. Är detta något jag måste bry mig om? Dock så tar det ju alltid emot att få upp felmeddelanden/varningar.

Varningar är till just för att man ska fixa dem, så det är helt rätt att inte bara "blunda". PHP klagar på att du refererar till variabler som inte har satts; som standard försöker PHP vara snäll och inte komplett dö, utan tolka dessa som en tom sträng och gå vidare med en varning. Vad du borde göra är att kontrollera med `isset()` ifall variabeln är satt — av funktionens natur så kommer den inte ge felmeddelanden om variabeln inte är satt, men däremot ett `false`. (Ett dåligt sätt att ta bort varningar är att tysta felmeddelanden med `@`: gör det ordentligt i stället.)

Skrivet av anon186159:

Sedan undrar jag hur man avgör när man ska använda == eller ===

Comparison Operators [PHP-manualen], How do the equality (== double equals) and identity (=== triple equals) comparison operators differ? [SO].

`===` jämför värde och typ. `==` jämför värde efter att PHP har kämpat med att omvandla värdena på båda sidor till samma typ. Eftersom PHP:s omvandlingsregler är rätt frikostiga så kan det senare ge just lustiga följder med strängen "0" och annat. `!==` är motsvarigheten till `!=`. Större än/mindre än-jämförelser leder till lite lustiga resultat som att `5 > "banan"` blir `true`, eftersom strängen "banan" booleanskt räknas som `true`, vilket motsvarar `1`, vilket är mindre än `5`. Jämför man bananer och heltal så har man dock större problem än PHP:s typning .

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Permalänk
Inaktiv

Okej, går nu över till mysqli (och fixar med allt annat ni skrev). Har dock stött på ett problem jag inte klarar att klura ut.

$A_ID = mysql_real_escape_string($_POST['A_ID']);

När jag gör om detta till mysqli_real_escape_string så vill den ha två variabler. Om jag förstod det rätt så ska det vara mysqli_real_escape_string($connection, $variable)? Men gör jag detta så blir det error för mig.

Min connect ser ut såhär:

$mysqli = new mysqli("$DBSERVER", "$DBUSER", "$DBPASS", "$DBNAME"); if ($mysqli->connect_errno) { echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error; }

Och slutligen ska mysqli_real_escape_string endast användas vid öppen anslutning annars retuneras värdet 0?

Och är det smart att ALLTID kolla om det även är samma typ (alltså använda ===). Alltså, kan man så ska man?

Permalänk
Hedersmedlem
Skrivet av anon186159:

$mysqli = new mysqli("$DBSERVER", "$DBUSER", "$DBPASS", "$DBNAME");

Det är onödigt att ha citationstecken runt variablerna; de bara gör att PHP tolkar det som en sträng, parsar ut variabeln och lägger den till strängen, och tolkar det sedan som ett argument till funktionen. Utan citationstecken så tolkas det direkt som ett argument, vilket är intentionen.

Skrivet av anon186159:

När jag gör om detta till mysqli_real_escape_string så vill den ha två variabler. Om jag förstod det rätt så ska det vara mysqli_real_escape_string($connection, $variable)? Men gör jag detta så blir det error för mig.

Du behöver inte `mysqli_real_escape_string` om du använder "prepared statements", vilket är att rekommendera generellt.

En kort demonstration av prepared statements med `mysqli` baserat på en sats du hade, rikligt kommenterat:

// Vi öppnar databaskopplingen, liksom du gjorde. Notera att jag inte har med // felhantering i detta exempel, men det kan du lägga till. $mysqli = new mysqli($DBSERVER, $DBUSER, $DBPASS, $DBNAME); // Först _förbereder_ vi frågan: detta innebär att vi definierar vad som är // inputvariabler, och säger till databasen att tolka detta. Ifall något är fel // i syntax så säger MySQL till redan här. Frågetecknen är placeholders för var // vi vill stoppa in variabler i nästa steg. $query = $mysqli->prepare(' INSERT INTO coin_bases (`id`, `A_ID`, `row`, `year`, `quality`, `value`, `type`, `country`, `notes`) VALUES (null, ?, ?, ?, ?, ?, ?, ?, ?)'); // Sedan _binder_ vi variabler till ovanstående "frågetecken". Första strängen // är "magisk": ett "i" betyder att den variabeln i ordningen ska bindas till // en `int`, ett "s" betyder sträng. Jag gissar att `year` också ska vara en // `int`; du har kanske fler saker som du tycker ska vara heltal, och i så fall // kan du modifiera därefter. Vad gäller egentligen alla tips du får så bör du // läsa manualen om funktionen innan du använder den. PHP:s manual är en av // språkets bästa resurser; mängden slarviga tips som finns att hitta på nätet // (givna med de bästa av intentioner) är en av dess sämsta :-) . $query->bind_param( 'isisssss', $_POST['A_ID'], $_POST['row'], $_POST['year'], $_POST['quality'], $_POST['value'], $_POST['type'], $_POST['country'], $_POST['notes']); // Nu _kör_ vi frågan på riktigt. $query->execute() or die('Fel i SQL-sats:<br>' . "\n" . $query->error); // Rent tekniskt hade vi kunnat köra fler `execute` efter att ha ändrat våra // invariabler (du behöver inte "binda om" — du band _referenser_ till // variablerna, inte värdena, så om du ändrar variablernas värden så kommer det // automatiskt uppfattas), och då kört samma fråga fast med andra värden. Här // vill vi bara köra en fråga, så vi är klara, och stänger butiken. $query->close();

På ett liknande sätt kan man binda output till variabler med `bind_result`. Se manualen för exempel.

Det är som sagt ett annorlunda sätt att jobba mot databasen, men det är mycket kraftfullare, och om man räknar in den extra tid man sparar på att behöva oroa sig för trivial SQL-injektion så är det sammanlagt mindre jobb (när man väl kan syntaxen). `mysqli` har två gränssnitt: ett "procedurellt" som är mer likt det gamla `mysql`-gränssnittet i syntax, där man kallar på funktioner som `mysqli_stmt_bind_result()`, och ett "objektorienterat", där man i stället jobbar med anslutningen som ett objekt genom vilket vilket man kallar funktioner som `$mysqli->bind_result()`. Det senare skulle jag säga är att föredra, då det är tydligare vilken anslutning man jobbar med och det är mindre att skriva.

Prepared Statements in PHP and MySQLi [Matt Bango="Bango"] var en kort och koncis initial genomgång av de saker som nämnts här; skadar inte att läsa liknande information från olika håll.

Notera att så fort som du bakar in PHP-variabler direkt i query-strängen så kringgår du säkerhetsmekanismen i "prepared statements". När du gör detta så ska varningsklockor ringa så att du har koll på vad du egentligen gör.

För utdata så gäller det fortfarande att alltid lägga exemeplvis `htmlspecialchars()` runt variabeln om det ska skrivas ut i HTML-dokumentet, och man ska aldrig "lita" på att datan man får in är "snäll".

Se även ett tidigare inlägg jag skrivit i frågan här på forumet.

Skrivet av anon186159:

Och är det smart att ALLTID kolla om det även är samma typ (alltså använda ===)?

Det beror på vad man vill kontrollera :-) . Båda varianterna finns av en anledning. Kruxet är att förstå vad "sant" och "falskt" betyder i PHP. Börjar man jobba med objekt tillkommer ytterligare en dimension i likhetsjämförelser.

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Permalänk
Medlem
Skrivet av anon186159:

$A_ID = mysql_real_escape_string($_POST['A_ID']);

När jag gör om detta till mysqli_real_escape_string så vill den ha två variabler. Om jag förstod det rätt så ska det vara mysqli_real_escape_string($connection, $variable)? Men gör jag detta så blir det error för mig.

Min connect ser ut såhär:

$mysqli = new mysqli("$DBSERVER", "$DBUSER", "$DBPASS", "$DBNAME"); if ($mysqli->connect_errno) { echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error; }

Det första argumentet i mysqli_real_escape_string är referensen till anslutningen. Den kan man kalla vad man vill, men du har ju valt $mysqli och inte $connection, därför fungerar det inte. Så i ditt fall skulle det vara:

mysqli_real_escape_string($mysqli, $variable)

Nu har du dock valt att öppna anslutningen objektorienterat, så då är det vettigare att fortsätta likadant:

$mysqli->real_escape_string($variable);

Ännu bättre är som redan sagts att använda prepared statements.

Tänk också på att om du vill använda referensen i en funktion så måste den finnas tillgänglig i den kontexten. Då får du antingen göra $mysqli global eller skicka in den som ett argument i funktionen.

Permalänk
Inaktiv

base_functions.php

function printCountryOptions() { include ('db_connect.php'); $query = $mysqli->prepare('SELECT sa FROM sa ORDER BY sa'); if ($stmt = $mysqli->prepare($query)) { /* execute statement */ $stmt->execute(); /* bind result variables */ $stmt->bind_result($sa); /* fetch values */ while ($stmt->fetch()) { echo ("<option value=\"$sa\">$sa</option>\n"); } /* close statement */ $stmt->close(); } $mysqli->close(); }

insert.php

... include ('function/base_functions.php'); ... <tr> <td>*Land:</td> <td> <select name="country"> <option value="Sverige">Sverige</option> <option value="---">---</option> <?php printCountryOptions();?> </select></td> </tr>

Jag prövade med att köra funktionen i test.php utan som funktion. Och det fungerade bra. Men när jag ropar in det som en funktion istället så får jag felmeddelandet:

Warning: mysqli::prepare() expects parameter 1 to be string, object given in C:\Users\Jonas\Desktop\localversionofcoin\wamp\www\function\base_functions.php on line 7

Permalänk
Medlem

Du kallar på "$mysqli->prepare" två gånger efter varandra med resultat som parameter.

Permalänk
Medlem
Skrivet av anon186159:

base_functions.php

function printCountryOptions() { include ('db_connect.php'); $query = $mysqli->prepare('SELECT sa FROM sa ORDER BY sa'); if ($stmt = $mysqli->prepare($query)) { /* execute statement */ $stmt->execute(); /* bind result variables */ $stmt->bind_result($sa); /* fetch values */ while ($stmt->fetch()) { echo ("<option value=\"$sa\">$sa</option>\n"); } /* close statement */ $stmt->close(); } $mysqli->close(); }

insert.php

... include ('function/base_functions.php'); ... <tr> <td>*Land:</td> <td> <select name="country"> <option value="Sverige">Sverige</option> <option value="---">---</option> <?php printCountryOptions();?> </select></td> </tr>

Jag prövade med att köra funktionen i test.php utan som funktion. Och det fungerade bra. Men när jag ropar in det som en funktion istället så får jag felmeddelandet:

Warning: mysqli::prepare() expects parameter 1 to be string, object given in C:\Users\Jonas\Desktop\localversionofcoin\wamp\www\function\base_functions.php on line 7

Du preparar ju två gånger.
Ändra:

$query = $mysqli->prepare('SELECT sa FROM sa ORDER BY sa');

till

$query = 'SELECT sa FROM sa ORDER BY sa';

Sen så lider din kod fortfarande av indenteringsproblem. Och varför envisas du med att inkludera din databasfil i varje funktion? Lägg den högst upp i scriptet och ändra till include_once('db_connect.php') så finns den tillgänglig i alla funktioner.

Permalänk
Inaktiv

Aha, tackar. Det gjorde susen!

Jag prövade att lägga in include_once i base_functions som du sa. Men det hängde inte alls med.

Okidoki, ska jobba vidare med intenderingen.

Permalänk
Inaktiv

Nu har jag skrivit om alla funktioner. Det som återstår är ett säkert inloggningssystem och ordna så att man kan lägga in metallvikt och sedan ändra metallpriset så att värdet blir korrekt med prisändringar för guld, silver osv. Vissa mynt har bara sitt värde i själva metallen. Sedan gå igenom intenderingen och diverse slarvfel.

Skaffat en github och släpper koden under GPLv2. Så får ordna ett installationssystem när jag är färdig med allt grundläggande.

https://github.com/intervet/CoinBase

Lite kommentarer till det som skrivits:

  • - Gått över till HTML5

  • - Inget stöd för IE6 längre

  • - Live-versionen kör jag på min Linux server (där har jag säkerhetstänk till fullo). Lokalt när jag utvecklar så kör jag wamp. Därav $DBUSER="root" $DBPASS=""

  • - A-ID är något man tilldelar själv som användare. Man kallar ett plastark för ett visst id. Sedan lägger man till mynt som; Rad: 1,1. 1,2. 1,3. 2,1 osv. Man lägger alltså in flera mynt på samma A-ID.

  • - Mynt och rullar ligger faktiskt i samma tabell. Skiljer ut dom genom is_roll. Sätter man inget värde så är standardvärde 0. Eftersom de flesta är ju faktiskt inte rullar.

  • - Självklart använder jag ett unikt INDEX id. Detta är dock man som använder inte ser röken av

.

Permalänk
Inaktiv

Utvecklingen och lärandet går i rasande takt!

Hade ett par säkerhetsfrågor.

Fråga 1 (help.php):

  • Räcker strip_tags? Är det rätt använt eller är det någon annan säkerhetsfunktion man skall använda? Eller kanske inte ens behöver ha en sådan då vi definerar variabeln till heltal? Men säg att det är en sträng - då skall strip_tags användas?

help.php

<?php //Declare variables $id = ''; $c = ''; //Get values from browser if ((int)isset($_GET['id'])) {$id = (int)strip_tags($_GET['id']);} if ((int)isset($_GET['c'])) {$c = (int)strip_tags($_GET['c']);} include 'template/head.php'; include 'function/help_functions.php'; printHelpgotofirst($id); ?> <ul class="tabs"> <?php printHelpmenu($id, $c); ?> </ul> <?php printHelpcontent($id); include 'template/end.php'; ?>

Fråga 2 (help_functions.php)

  • Är det EXTREMT dumt att använda eval? Läst mycket varningar om det. Men jag har hjälpsektionen lite som ett CMS. Och en av hjälpsidorna skriver ut en tabell med myntmästare och deras myntmästarmärken. Detta görs visa att hämta värdena via php/MySQL. Ur en säkerhetssynpunkt är det kanske bäst att dumpa eval och göra en statisk tabell (myntmästare uppdateras inte direkt ofta)? Eller går det bra? Enda sättet att lägga in phpkod i databasen är att manuellt aktivera enphp (int) och skriva in koden via phpMyAdmin.

help_functions.php

<?php .... function printHelpcontent($idp) { //Define variable $content = ''; //Get content! include 'db_connect.php'; $query = "SELECT * FROM content WHERE ID=?"; if ($stmt = $mysqli->prepare($query)) { /* execute statement */ $stmt->bind_param('i', $idp); $stmt->execute(); /* bind result variables */ $stmt->bind_result($id, $rang, $title, $c, $e); /* fetch values */ while ($stmt->fetch()) { $content = $c; $ean = $e; } /* close statement */ $stmt->close(); } $mysqli->close(); //Print content! if ($ean == 1){eval ('?>'. $content .'<?php ');} else {echo $content;} }?>

Permalänk
Legendarisk
Skrivet av anon186159:

Räcker strip_tags? Är det rätt använt eller är det någon annan säkerhetsfunktion man skall använda? Eller kanske inte ens behöver ha en sådan då vi definerar variabeln till heltal? Men säg att det är en sträng - då skall strip_tags användas?

Du måste behandla din data efter det sammanhang du vill använda den i; ska du presentera uppgifter i HTML måste du behandla det på ett sätt, i SQL ett annat, etc. Eftersom att du inte avser att behandla innehållet i id och c som HTML så behöver du inte göra så – i det här fallet bör du istället kontrollera om strängen beskriver ett heltal innan du försöker använda den. Vidare så bör du inte använda strip_tags() i säkerhetssyfte; dels formaterar den om strängen (vill du det?) och dels är den inte ett tillräckligt skydd mot XSS. Ska du skriva ut den tillsammans med HTML så bör du istället använda htmlspecialchars().

if ((int)isset($_GET['id']))

isset() returnerar redan sant eller falskt, att konvertera värdet till ett heltal innan du kontrollerar om det i sin tur verkar vara truthy/falsy gör ingen nytta.

$type_new = mysqli_real_escape_string($mysqli, strip_tags($_POST['type_new'])); $query = "INSERT INTO `coin_bases` (/* ... */) VALUES (/* ... */, ?)"; $stmt->bind_param(/* ... */, $type_insert);

När du använder prepared statements ska du inte escapa manuellt. Det är även viktigt att validera uppgifter innan du försöker skicka dessa till databasen; även om du är skyddad mot injections så kan det vara skadligt att acceptera uppgifter som databasen inte kan hantera (t.ex. text i ett numeriskt fält), eller orimliga/felaktiga värden som kan påverka ditt eget program på oavsedda sätt.

Visa signatur

Abstractions all the way down.

Permalänk
Inaktiv
Skrivet av Tunnelsork:

$type_new = mysqli_real_escape_string($mysqli, strip_tags($_POST['type_new'])); $query = "INSERT INTO `coin_bases` (/* ... */) VALUES (/* ... */, ?)"; $stmt->bind_param(/* ... */, $type_insert);

När du använder prepared statements ska du inte escapa manuellt. Det är även viktigt att validera uppgifter innan du försöker skicka dessa till databasen; även om du är skyddad mot injections så kan det vara skadligt att acceptera uppgifter som databasen inte kan hantera (t.ex. text i ett numeriskt fält), eller orimliga/felaktiga värden som kan påverka ditt eget program på oavsedda sätt.

Förstod inte helt vad du menade. Menar du att jag ska använda mig av mysqli_real_escape_string?

Permalänk
Medlem
Skrivet av anon186159:

Utvecklingen och lärandet går i rasande takt!

Hade ett par säkerhetsfrågor.

...

Fråga 2 (help_functions.php)

  • Är det EXTREMT dumt att använda eval? Läst mycket varningar om det. Men jag har hjälpsektionen lite som ett CMS. Och en av hjälpsidorna skriver ut en tabell med myntmästare och deras myntmästarmärken. Detta görs visa att hämta värdena via php/MySQL. Ur en säkerhetssynpunkt är det kanske bäst att dumpa eval och göra en statisk tabell (myntmästare uppdateras inte direkt ofta)? Eller går det bra? Enda sättet att lägga in phpkod i databasen är att manuellt aktivera enphp (int) och skriva in koden via phpMyAdmin.

help_functions.php

<?php .... function printHelpcontent($idp) { //Define variable $content = ''; //Get content! include 'db_connect.php'; $query = "SELECT * FROM content WHERE ID=?"; if ($stmt = $mysqli->prepare($query)) { /* execute statement */ $stmt->bind_param('i', $idp); $stmt->execute(); /* bind result variables */ $stmt->bind_result($id, $rang, $title, $c, $e); /* fetch values */ while ($stmt->fetch()) { $content = $c; $ean = $e; } /* close statement */ $stmt->close(); } $mysqli->close(); //Print content! if ($ean == 1){eval ('?>'. $content .'<?php ');} else {echo $content;} }?>

Jag fattar inte varför du gör så överhuvudtaget. Det borde ju vara exakt samma sak som att bara skriva $content, eller?

edit: ok, du har PHP-kod i $content om ean == 1. Det låter rätt illa ja. Blir det inte bökigt att ändra den koden i databasen om du behöver göra uppdateringar?

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Hedersmedlem
Skrivet av anon186159:

Fråga 1 (help.php):

  • Räcker strip_tags? Är det rätt använt eller är det någon annan säkerhetsfunktion man skall använda? Eller kanske inte ens behöver ha en sådan då vi definerar variabeln till heltal? Men säg att det är en sträng - då skall strip_tags användas?

int-kastningen returnerar alltid ett heltal, och inte en sträng. Ett heltal kan inte innehålla HTML- eller PHP-taggar, så det hjälper inte mycket här. Eftersom vi ska använda prepared statements där vi definierar in-argumenten som heltal så är det också visst dubbelarbete.

`strip_tags()` är ingen "säkerhetsfunktion", utan någon som ska användas när man helt enkelt vill ha bort taggar, av någon anledning.

Vad som är "säkerhet" beror på vad man ska använda datan till. Ska man sätta in det i en databas så är `mysql_real_escape_string()` en säkerhetsfunktion, men än hellre använder man som sagt prepared statements. En databas kan lagra både PHP-taggar och HTML-taggar utan problem, så det är ingen fara i sig att låta detta vara en del av input. När man skriver ut denna information så ska man ju dock använda `htmlspecialchars()`, som då blir en säkerhetsfunktion, då den hindrar exempelvis skriptinjektion, oönskade iframes, elaka taggar som förstör layout, etc. Om man tar data som i något steg kan ha kommit från en användare och kastar in den i `eval()` eller dylikt så får man ha bra koll på att det inte är något oväntat däri.

I detta fall kanske du mer är intresserad av om det handlar om "giltiga ID" eller något, men det är troligen snarare ett problem för databasfrågan än PHP i sig (man hade ju kunnat ta bort negativa ID, men som sagt: det kommer ju ändå inte ge någon träff i databasen, och hanteras som icke-existerande där).

Skrivet av anon186159:

<?php //Declare variables $id = ''; $c = '';

I stället för att fördeklarera variabler så kan du kontrollera dessa med `isset()` senare. Fördeklaration är sällan nödvändigt, och tyder snarare på att man krånglar till någon logiksteg i onödan.

Skrivet av anon186159:

//Get values from browser if ((int)isset($_GET['id'])) {$id = (int)strip_tags($_GET['id']);} if ((int)isset($_GET['c'])) {$c = (int)strip_tags($_GET['c']);}

Den första kastningen på varje rad är onödig. `isset()` ger `true` eller `false`, vilket alltid går att int-kasta till `1` eller `0`. Efter att det nu gjorts så kommer `if` åter kasta dessa till `true` eller `false` för villkorets skull, så typkastningen lägger bara till ett par steg för PHP.

Ett sätt att sätta defaultvärden kompakt är en konstruktion likt:

$id = isset($_GET['id']) ? (int)$_GET['id'] : false;

Denna konstruktion kallas för ternary operator. Om `$_GET['id']` är satt så sätts `$id` till `(int)$_GET['id']`; annars sätts `$id` till `false`. Jag ger standardvarningen att denna konstruktion lätt blir fruktansvärt svår att läsa om man trycker in flera steg och jämförelser, men det märker man själv med tiden. Jag har sett vissa som helt avråder ifrån den, men det tycker jag är fel: den finns, då får man använda den. Att den används med måtta och förstånd är upp till programmeraren.

int-kastning av något som inte kan tolkas som ett giltigt heltal (strängen " 15 gastar" tolkar PHP i heltalskontext som "15", så vad som är "giltigt" är inte helt uppenbart) ger heltalet 0. Skickar någon in `id=kanin` i ?:-testet ovan så kommer `id` sättas till 0. Skickar någon inte in något `id` alls så kommer `id` sättas till `false`. Genom `===` kan vi särskilja dessa (även från det fakiskt giltiga `id=0` som någon kanske vill titta på). Vill man att `id=kanin` ska ge ett felmeddelande eller något så får man kontrollera detta extra, men det handlar om beteende som en användare medvetet gör för att krångla, så jag känner inte att man behöver lägga tid på att behandla det bättre än att se till att det inte innehåller något skadligt.

Skrivet av anon186159:

Är det EXTREMT dump att använda eval? Läst mycket varningar om det. Men jag har hjälpsektionen lite som ett CMS. Och en av hjälpsidorna skriver ut en tabell med myntmästare och deras myntmästarmärken. Detta görs visa att hämta värdena via php/MySQL. Ur en säkerhetssynpunkt är det kanske bäst att dumpa eval och göra en statisk tabell (myntmästare uppdateras inte direkt ofta)? Eller går det bra? Enda sättet att lägga in phpkod i databasen är att manuellt aktivera enphp (int) och skriva in koden via phpMyAdmin.

Av beskrivningen eller koden så förstår jag inte varför `eval()` skulle vara en lösning på någonting alls i detta fall. PHP kan hämta data ur databaser och presentera det själv: vad är meningen med `eval()` här? Vill du att din `$c` ska innehålla PHP-kod? Varför? Om inte så finns det ingen anledning att använda `eval()`, och jag ser inte vad som skulle motivera det här.

Du kan skriva ut HTML-kod direkt ur en variabel hämtad från en databas, om det är det du försöker med. Ifall du vill att användare ska kunna skriva egna sådana stycken som ska presenteras som HTML-kod så kan det vara lite vanskligt att ge dem frikort för att stoppa in vad som helst (vilket ju då kan inkludera PHP-kod och annat). Om man är osmidig/naiv så tänker man "aha, jag börjar snickra på någon sorts egen parser med vitlistade taggar!". Om man inte vill bli galen så använder man något färdigt bibliotek för BBCode, Markdown, reStructuredText eller liknande och låter användare skriva med den syntaxen.

EDIT: Ah, som personen ovan noterade så vill du ha just PHP-kod i visst innehåll.

Om du vill tillåta användare att ändra detta själva genom ett gränssnitt så känns det som att du behöver göra en rätt invecklad lösning för att hålla det säkert; typ implementera ett eget templatespråk där t ex texten `{{mynttabell}}` parsas och ersätts av en tabell som genereras av fördefinierad PHP-kod. Det låter lite som att du försöker återimplementera Wikipedia, och det är inte gjort på en handvändning. Det går att använda färdiga sådana templatespråk, men frågan är om det inte är överdrivet avancerat för fallet i fråga. Dina hjälpsidor kanske enklare kan vara filer, liksom resten av din sida?

Vill du att "vem som helst" ska kunna redigera så skulle man exempelvis kunna låta dem inkomma med pull requests på Github, men det tar bort alla utom en fraktionen som är tillräckligt teknikvana. Överlappet mellan myntsamlare och Gitanvändare är nog rätt litet. Att låta vem som helst skriva PHP-kod som körs skarpt är rätt bananas, så om det är ett krav att vem som helst ska redigera så kanske just ett templatespråk trots allt är den bästa lösningen, där du själv får skriva fördefinierade databasfrågor som de kan använda. Notera att det blir en del jobb, och att statiska filer kanske är enklare för alla parter.

Ett annat sätt är att tänka om problemet: kanske hjälpsidorna inte är rätt plats för en sådan mynttabell. Den kanske kan ligga på en sida som är separerad från ordinarie hjälptopics, om nu de måste vara webbredigerbara.

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Permalänk
Medlem
Skrivet av anon186159:

Räcker strip_tags? Är det rätt använt eller är det någon annan säkerhetsfunktion man skall använda? Eller kanske inte ens behöver ha en sådan då vi definerar variabeln till heltal? Men säg att det är en sträng - då skall strip_tags användas?

Eftersom du jobbar med siffror så är de ju siffror och inget annat. Alltså behöver du inte det.
strip_tags är inte heller en lösning på allt. Vad du ska använda beror på situationen.

Skrivet av anon186159:

Är det EXTREMT dumt att använda eval?

Ja.
Vad vill du göra?

Permalänk
Inaktiv

OFF TPOPIC: Alltså helt ärligt kärlek till er som svarar och kärlek till Sweclockers! Och HERREGUD vilken lång tråd
----
Har lagt tre hela timmar på att fixa intenderingen i varenda fil. Nästa gång gör jag rätt från början! x(
Har tagit bort eval. Hjälpsektionen skrivs in via systempanelen i ett TinyMCE-gränsnitt (om det var någon som tyckte det var lite snurrigt med vad jag menade. Kanske borde ta och skriva en länge sammanfattning så att gemenemann förstår vad det är jag har skapat...). Och ska ersätta alla output som jag anser kräver det med en htmlspecialchars().

En liten annan säkerhetsfundering. Kan exemeplvis $_GET ge tiillfälle för PHP-injections?
----
Jag har ett konstigt problem som jag inte förstår varför det sker så.

Kortfattat är det såhär:

  • Jag har en sökfunktion

  • Den skriver ut en tabell

  • Sedan räknar den ut det totala värdet av alla mynt som sökningen får en träff på (jobbar ATM på att även summera in mynt som baseras på sitt metallvärde, men detta kan ni bortse från. Koden fungerar utan någon error så som den är nu.)

  • Mitt problem är att av någon anledning VÄGRAR PHP skriva ut det totala värdet under tabellen och skriver den alltid överst.

  • Spelar ingen roll var jag placerar mitt echo. Har prövat varenda ställe.

  • Har detta något med att göra hur PHP prioriterar vilken kod den kör i vilken ordning möjligtvis?

search.php (mycket kod, men jag ropar helt enkelt på en funktion som sedan skriver ut sökresultaten.

<?php ... search($A_ID, $quality, $year, $type, $country, $is_roll); ... ?>

search_functions.php

<?php function search($dbA_ID, $dbquality, $dbyear, $dbtype, $dbcountry, $dbis_roll) { include 'db_connect.php'; $no = 1; $i = 1; //Convert search input for MySQL $likedbA_ID = '%' . $dbA_ID . '%'; $likedbquality = '%' . $dbquality . '%'; $likedbyear = '%' . $dbyear . '%'; $likedbtype = '%' . $dbtype . '%'; $likedbcountry = '%' . $dbcountry . '%'; $likedbisroll = '%' . $dbis_roll . '%'; $query = "SELECT * FROM coin_bases WHERE A_ID LIKE ? AND quality LIKE ? AND year LIKE ? AND type LIKE ? AND country LIKE ? and is_roll LIKE ? ORDER BY row, A_ID"; if ($stmt = $mysqli->prepare($query)) { $stmt->bind_param( 'ssssss', $likedbA_ID, $likedbquality, $likedbyear, $likedbtype, $likedbcountry, $likedbisroll); /* execute statement */ $stmt->execute(); /* bind result variables */ $stmt->bind_result($id, $A_ID, $rowd, $year, $quality, $value, $type, $country, $notes, $weight, $quantity, $metal_id, $metal_value, $file_folder, $is_roll); while ($stmt->fetch()) { if ($i == 1) { echo " <table class=\"CSSTableGenerator\"> <tr> <td width=\"110\">Ark-ID</td> <td>Rad</td> <td>År</td> <td>Kvalité</td> <td>Värde</td> <td>Valör</td> <td>Land</td> <td>Notering</td> <td>Ändra</td> </tr>"; $i = 0; $no = 0; } if ($is_roll == '1') { $write_roll = " <b>Är en rulle</b>"; } else { $write_roll = ''; } echo " <tr> <td>$A_ID$write_roll</td> <td>$rowd</td> <td>$year</td> <td>$quality</td> <td>"; if ($value > 0) { echo $value; } if (!$value || $value == 0) { printMetalValue($id); echo " <i>m</i>"; } echo "</td> <td>$type</td> <td>$country</td> <td>$notes</td> <td><a href=\"edit.php?id=$id\"><img src=\"images/page_white_edit.png\" alt=\"\" width=\"16\" height=\"16\" />Ändra</a></td> </tr>"; } } //END if ($stmt = $mysqli->prepare($query)) //Now we calculate the SUM value $query = "SELECT value, SUM(value) FROM coin_bases WHERE A_ID LIKE ? AND quality LIKE ? AND year LIKE ? AND type LIKE ? AND country LIKE ? and is_roll LIKE ? ORDER BY row, A_ID"; if ($stmt = $mysqli->prepare($query)) { $stmt->bind_param( 'ssssss', $likedbA_ID, $likedbquality, $likedbyear, $likedbtype, $likedbcountry, $likedbisroll); $stmt->execute(); $stmt->bind_result($value, $sum_value); while ($stmt->fetch()) { if ($i == 0) {echo "Totalt värde: $sum_value";} } } //END if ($stmt = $mysqli->prepare($query)) $mysqli->close(); //Close connection to Mysql }// END search Func. ?>