PHP (Windows): Ausgabe Shell-Abfrage -> Array

WulfmanGER

Commander
Registriert
Juli 2005
Beiträge
2.272
Hallo zusammen,

für eine kleine LAN-HP-Spielerrei benötige ich für die physikalischen Laufwerke (C, D, E, F, G, Z) die Laufwerksgröße und wieviel frei ist. Das bekomme ich z.b. mit php mittels disk_free_space und disk_total_space. Jetzt fahre ich diese Abfrage 6x für free und 6x für total. Problem: wenn ein neues Laufwerk dazu kommt, muss ich in dem Script das Array für Laufwerk + Name des Laufwerkes erweitern.

Jetzt hab ich eine einfachere Methode (für PHP unter Windows (10) )gefunden:

shell_exec('wmic logicaldisk list Brief'); (den befehl ohne das shell_exec kann man auch normale in der Windows-CLI aufrufen)

Hier hab ich die Laufwerksbuchstaben, Größe, Frei und Name in einer Übersicht - und zwar immer passend zu der Anzahl vorhandene Laufwerke (die kann sich ändern)

Ich bekomme das Ergebnis nur nicht in ein Array gesplittet - mir fehlt derzeit noch ein Ansatz.
Code:
DeviceID  DriveType  FreeSpace     ProviderName                                           Size          VolumeName
C:        3          438033813504                                                         510519480320  System

Das Array sollte am Ende z.b. so ausschauen (für diese Art Array hab ich bereits die passende Ausgabe):

Code:
$hd = array
(
  'laufwerk' => array
  (
      'c',
      'd',
  ),
  'name' => array
  (
      'System',
      'Test 1',
  ),
  'free' => array
  (
  '10000000',
  '20000000',
  ),
  'total' => array
  (
'200000000',
'300000000'
  )
);

Ausgabe erfolgt dann über eine while-schleife wo ich das Array durchrattere. FREE und TOTAL werden noch addiert - aber das ist ja kein Problem. GGF. würde ich das ganze sogar in eine Datenbank schreiben ... für Nachhaltige Statistik :)

Ich suche letztendlich eine Möglichkeit/Methode um solche SHELL-Ausgaben in PHP auszuwerten. Ob jetzt diese oder eine ganze reihe anderer Windows-Ausgaben ....

Danke schon mal für kreative Vorschläge :)


PS: Zeilenweise bekomme ich das ganze übrigens mit explode("\n", $result); ins Array - aber ich habe in der Ausgabe ja Zeilen und Spalten die zu trennen wären ...
 
Schau ob es dort ein explizites Zeichen zwischen den einzelnen Werten gibt. Z.B ein Leerzeichen, dass dann nochmal mit explode getrennt wird und je Array z.B Array[0] -> Laufwerk, Array[3] -> Freier Speicher usw..
 
  • Gefällt mir
Reaktionen: new Account()
leider nicht - die Idee mit einem Zeichen hatte ich auch - aber wenn du dir die Ausgabe selber mal anschaust (wenn du auf ein Windows-System zugreifen kannst): Leerzeichen hab ich hier nur. Und die Idee hatte ich gerade auch schon ... Das würde mit DeviceID, DriveType, Freespace gehen - und dann kommt Providername (nur gefüllt, wenn Netzlaufwerk) => ist ein Netzlaufwerk dabei hab ich jetzt durcheinander. Bei VolumenNamen hab ihc zudem wieder einen Leerschritt drin "Test 1" - klingt also sehr fehleranfällig.

Besser als Explode ist: preg_split('/[\r\n]+/', $result, -1, PREG_SPLIT_NO_EMPTY); <- damit hab ich dann unnötige Leerzeilen am Ende weg. Aber das Ergebnis je Array-Eintrag ist gleich und den muss ich jetzt auseinander nehmen ....
 
Mein Gedanken war folgendermaßen:

Wenn die oben genannte Reihenfolge also
Code:
DeviceID  DriveType  FreeSpace  ProviderName Size   VolumeName
immer gleich ist und nur bei ProviderName je Netzwerk entweder Wert vorhanden oder nicht, so hast du zwei Möglichkeiten:

1. Da zwischen ProviderName jeweils FreeSpace(also Zahlenwert) und dahinter Size(Zahlenwert) vorhanden ist, und ProviderName wohl kein Zahlenwert besitzt, so prüft man dem 4 Array ob Zahl oder nicht, wenn ja, dann gibt es keinen Wert in ProviderName(sprich kein Netzwerk.... usw..).

2. Diese Möglichkeit beläuft sich darauf, dass wenn Leerzeichen nur als Trenner vorhanden sein sollten, du anhand der Arrayzahl je Zeile feststellen kannst, ob ProviderName einen Wert hat oder nicht, danach sollte die Logik klar sein.

edit: hab ohne durchzulesen es gepostet, habs etwas editiert^^
 
Zuletzt bearbeitet:
"du anhand der Arrayzahl je Zeile " <- das Array was ich mit Explode bzw. preg_split rausbekomme ist ganz simple
[1] C: 3 438033813504 510519480320 System

Ein Lösungansatz wäre die Erkenntnis das ProviderName scheinbar (schlecht zu testen...) mit \\ anfangen muss. DeviceName endet mit : ...DriveType, Freespace, Size sind IMMER Zahlen und ohne Leerschritte. VolumenName fängt immer mit einem Buchstaben an. Da zielt deine #1 drauf hinaus?

Das könnte man also mit einem Umständlichen Script rausarbeiten ... puhhh ....

Ich hab jetzt gerade noch rausgefunden: man kann die wmic-Ausgabe mit WHERE einschränken. WHERE DeviceType=3 und ich bekomme nur Datenträger angezeigt. 4 Sind wohl die Netzlaufwerke - brauch ich nicht.

Damit sieht der Aufbau etwas einfacher aus:
Ich weiß ich habe
2 Zeichen am Anfang jeder Zeile -> diese 2 => ab in das NEUE Array (nach Muster im Start-Thread)
Danach lösche ich alle leerschritte - jetzt kommt immer 1 Zeichen -> brauche ich hier nicht - verwerfe ich. Wieder leerschritte löschen -> jetzt wird es kniffeliger ... hier kann von 1 bis x div. Anzahl Ziffern stehen. Ich müsste also rausspeichern bis zum nächsten ersten Leerschritt ... dann kommt der nun immer leere ProviderName ... ich lösche also weiter Leerschritte ... dann bin ich bei Size ... bis zum ersten Leerschritt. VolumenNamen: vom ersten bis letzten Zeichen alles speichern.

Irgendwie hab ich bei beiden Lösungen das gefühl das es gefrickel ist und das es vielleicht auch schöner geht? ;)
 
  • Gefällt mir
Reaktionen: leonM
Hehe, ich glaube das Auslesen der Laufwerke geht schöner aber da müsste ich wieder gucken, was so PHP kann. Ich weiß, dass PHP da eigentlich eine viel simplere Lösung hat(glaube ich, ist auch lange her^^)

edit: Nur als Beispiel:

[1] C: 3 438033813504 510519480320 System

explode(" ",[1]);
if(!is_numeric(newA[4],0))
echo "Nö, kein Netzwerkwert";
else
echo "ja";

oder

if(count(newA)==5)
echo "Netzwerkwert vorhanden";
else
echo "Nö";

Somit weiß du, was bei dieser Zeile welcher Array was bedeutet bzw. was er ist. Und das defacto muss für die anderen Zeilen auch gemacht werden.
 
Zuletzt bearbeitet:
lol ... ich greife deinen ersten Vorschlag noch mal auf ... Leerschritte sind das Trennzeichen .... und zwischen jeder Spalte sind immer ZWEI LEERschritte .... und in keinen der Spalteninhalte sollten 2 Leerschritte vorkommen (nur bei VolumeName - aber das liegt ja an MIR wie ich meine Datenträger benenne!)

1) ich schreibe jede Zeile der Ausgabe in ein Array (mit preg_split).
2) ich lese per Schleife jeden Array-Eintrag aus. Wobei Array[0] = Überschriften -> Drop.
3) Das Auslesen erfolgt preg_split('/ +/', $result, -1, PREG_SPLIT_NO_EMPTY); <- vor dem Plus sind 2 Leerschritte

Damit erstelle ich mir ein Temporäres Array das ich dann gemütlich auslese und in mein Zielarray schreibe (beim reinschreiben noch ein trim()). Dann wäre es das ...
 
Zuletzt bearbeitet: (preg_split korrigiert)
Hauptsache du kommt weiter^^. Hab wieder oben etwas editiert aber du bist ja schon auf dem Weg zur Lösung, daher^^
 
jepp - gemeinsam Brainstormen hilft immer wieder :)

Danke :)
Ergänzung ()

Nachtrag da ich es selber hasse bei Google exakt mein Problem zu finden und dann der Kommentar vom TE "Hab die Lösung selber gefunden" und was mit mir? ;) Ich darf weitersuchen ... daher hier die Lösung:

Code:
$freiGesamt =0; $totalGesamt = 0;
$result =  shell_exec("wmic logicaldisk where \"DriveType='3'\" list brief"); # 3 = LocalDisks
$wllb = preg_split('/[\r\n]+/', $result, -1, PREG_SPLIT_NO_EMPTY); # erstellt Array - je Zeile ein Eintrag
$wllb_anzahl = count ($wllb) -1; # wie groß ist das Array (-1 wegen Überschrift)
$i = 1; # (0 = Überschrift, daher start bei 1)
while ($i <= $wllb_anzahl)
{
    $hd_temp[]  = preg_split('/  +/', $wllb[$i], -1, PREG_SPLIT_NO_EMPTY); #erstellt aus jeder Zeile ein eigenes Array
    $hd['laufwerk'][] = $hd_temp[0][0]; # Laufwerksbuchstabe
    $hd['free'][] = $hd_temp[0][2]; # FreeSpace
    $freiGesamt += $hd_temp[0][2];
    $hd['total'][] = $hd_temp[0][3]; # TotalSpace
    $totalGesamt += $hd_temp[0][3];
    $hd['name'][] = $hd_temp[0][4]; # Name des Datenträgers
    $i++; 
    $hd_temp ="";
}
    $hd['name'][] = "Gesamt";
    $hd['laufwerk'][] = "";
    $hd['free'][] = $freiGesamt;
    $hd['total'][] = $totalGesamt;
Quellcode-Reduzierung von um ca. 50 Zeilen ;). Zudem jetzt flexible (SATA-HDD per Wechselrahmen dran ... Go! ;) ).

Danach kann man das gemütlich weiterverabreiten.

Wie oben angedeutet: das ganze funktioniert nur mit PHP unter Windows.


Erklärung zu DriveType:
6 steht für: RAM Disk
5 steht für: Compact Disc
4 steht für: Network Drive
3 steht für: Local Disk
2 steht für: Removable Disk
1 steht für : No Root Directory

5 hab ich nicht, 6 brauch ich nicht, 5??? hä? ;) ... 2 ist noch interessant. Aber das darf jetzt jeder selber raustüfteln :)
 
Zuletzt bearbeitet:
Weiterer Ansatz: Gehe Zeichenweise vor. Die Werte stehen immer genau unter der Überschrift. Analysiere in der ersten Zeile die Anfangsposition jeder Überschrift und merke Dir diese. Lese in allen weiteren Zeilen die Werte von den Anfangspositionen bis zum nächsten Leerzeichen.
 
Sehe spontan zwei Optionen.

1. Feste Feldbreite. Also scanf dagegen werfen.
2. Per Regex replace alle Leerzeichen \s+ auf eines einstampfen und dann String.split entlang jenes Leerzeichens.

sei dir aber im Klaren, daß shell() immer a ein Sicherheitsproblem ist und b Portabilität bis zur Unmöglichkeit erschwert.
 
Zurück
Oben